在 Office 中,可以在 PPT 里面插入表格,插入表格有好多不同的方法,對應 OpenXML 檔案存盤的更多不同的方式,本文來介紹如何讀取 PPT 內嵌 xlsx 格式的表格的方法
讀取方法和 dotnet OpenXML 讀取 PPT 內嵌 ole 格式 Excel 表格的資訊 差不多,對于 Office 2019 以上版本,插入 Excel 表格用的不是 OLE 檔案的方式,而是放入一個 xlsx 檔案
在 Slide.xml 頁面里面,存放的是在 GraphicFrame 下的內容,簡化的 OpenXML 檔案如下
<p:graphicFrame>
<p:nvGraphicFramePr>
<p:cNvPr id="9" name="表格 1" />
</p:nvGraphicFramePr>
<p:xfrm>
<a:off x="5405438" y="3241675" />
<a:ext cx="3438525" cy="2009775" />
</p:xfrm>
<a:graphic>
<a:graphicData uri="http://schemas.openxmlformats.org/presentationml/2006/ole">
<mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<mc:Choice xmlns:v="urn:schemas-microsoft-com:vml" Requires="v">
<p:oleObj spid="_x0000_s1026" name="作業表" r:id="rId3" imgW="3438630" imgH="2009788" progId="Excel.Sheet.12">
<p:embed />
</p:oleObj>
</mc:Choice>
<mc:Fallback>
<!-- 忽略 -->
</mc:Fallback>
</mc:AlternateContent>
</a:graphicData>
</a:graphic>
</p:graphicFrame>
插入的 rId3 的資源對應的內容如下
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/package" Target="../embeddings/Microsoft_Excel_Worksheet.xlsx" />
</Relationships>
也就是說插入到頁面的對應的 xlsx 檔案存放路徑如下
ppt\embeddings\Microsoft_Excel_Worksheet.xlsx
和讀取 OLE 的 xls+ 方式不同的在于不需要讀取 OLE 檔案拿到 xlsx 檔案,只需要通過 Part 讀取即可,通過如上代碼可以看到在 Slide 頁面存放的代碼幾乎相同,需要加上一點判斷邏輯,才能決定是從 Part 讀取還是從 OLE 檔案讀取
通過判斷 part.ContentType 是 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" 的內容,即可了解是嵌入 xlsx 檔案,而不是 ole 格式檔案
讀取的邏輯如下
using var presentationDocument = PresentationDocument.Open(file.FullName, false);
var slide = presentationDocument.PresentationPart!.SlideParts.First().Slide;
var graphicFrame = slide.CommonSlideData!.ShapeTree!.GetFirstChild<GraphicFrame>()!;
var graphic = graphicFrame.Graphic!;
var graphicData = https://www.cnblogs.com/lindexi/p/graphic.GraphicData!;
var alternateContent = graphicData.GetFirstChild()!;
var choice = alternateContent.GetFirstChild()!;
var oleObject = choice.GetFirstChild()!;
Debug.Assert(oleObject.GetFirstChild() != null);
var id = oleObject.Id!;
var part = slide.SlidePart!.GetPartById(id!);
Debug.Assert(part.ContentType =="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
再加上判斷當前的 Graphic 期望使用的應用
// 預期字串是 “Excel.Sheet.12” 等內容
var isEmbedExcel = oleObject.ProgId?.Value?.StartsWith("Excel.Sheet", StringComparison.OrdinalIgnoreCase) is true;
Debug.Assert(isEmbedExcel);
將 Part 讀取放入到本地檔案,用于后續決議 Xlsx 檔案,為什么不能通過 part.GetStream 的方式,對回傳的 Stream 進行讀取即可?原因是此 Stream 是不支持隨機訪問的,這個 Stream 是從 System.IO.Packaging 拿到的,為了解決 N 多的坑,設計為不支持隨機讀取,只能順序讀取,而在決議 Xlsx 時,需要進行隨機讀取,否則就需要將整個檔案內容都加載到記憶體,為了減少記憶體的占用,存放到檔案
var tempFolder = @"F:\temp";
if (!Directory.Exists(tempFolder))
{
tempFolder = System.IO.Path.GetTempPath();
}
var xlsxFile = System.IO.Path.Combine(tempFolder, System.IO.Path.GetRandomFileName() + ".xlsx");
using (var fileStream = File.OpenWrite(xlsxFile))
{
using var partStream = part.GetStream(FileMode.Open,FileAccess.Read);
partStream.CopyTo(fileStream);
}
后續就是讀取 xlsx 的邏輯
using var spreadsheetDocument = SpreadsheetDocument.Open(xlsxFile, false);
var sheets = spreadsheetDocument.WorkbookPart!.Workbook.Sheets;
更多讀取 Excel 的方法請看 C# dotnet WPF 使用 OpenXml 決議 Excel 檔案
本文以上的測驗檔案和代碼放在github 和 gitee 歡迎訪問
可以通過如下方式獲取本文的源代碼,先創建一個空檔案夾,接著使用命令列 cd 命令進入此空檔案夾,在命令列里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 75c6c17055d7c254e648b7c1836f0657c72fc77a
以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼之后,進入 Pptx 檔案夾
更多請看 Office 使用 OpenXML SDK 決議檔案博客目錄
更多參考:
- [MS-OFFDI].pdf
- [MS-XLS].pdf
- [MS-OI 29500].pdf
博客園博客只做備份,博客發布就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可,歡迎轉載、使用、重新發布,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布,如有任何疑問,請與我[聯系](mailto:[email protected]),
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/354380.html
標籤:.NET Core
上一篇:手把手教你學Dapr - 1. .Net開發者的大時代
下一篇:[WPF] 制作一個彩虹按鈕
