前言

本文讨论的仅针对微软Office 2007以后的(OOXML定义)PowerPoint文档,Office 2007以前的用二进制格式定义的(ppt格式)文档不在本文讨论范围。

一、依赖类库

本文需要依赖两个免费的第三方类库:DocumentFormat.OpenXml和FreeSpire.Doc。

DocumentFormat.OpenXml用于加载解析pptx文档,FreeSpire.Doc用于解析pptx中嵌入的doc文档内容,详见解析嵌入的doc的文本。

二、解析步骤

1.引入库

通过Nuget引入类库

<packages>
<package id="DocumentFormat.OpenXml" version="2.13.0" targetFramework="net452" />
<package id="FreeSpire.Doc" version="7.11.0" targetFramework="net452" />
</packages>

2.读取数据

PPTX中的文本内容主要以三种形式存储。1、直接保存在slide*.xml文件的节点数据;2、以oleObject对象的形式存储在word文档中;3、以oleObject对象的形式存储在bin文件中。接下来针对这三种情况分别分析如何解析获取内容。

首先需要读取pptx文件,解析每一个页面的slide对象

using (var presentationDocument = PresentationDocument.Open(filePath, false))
{
var presentationPart = presentationDocument.PresentationPart;
var presentation = presentationPart.Presentation;
// 先获取页面
var slideIdList = presentation.SlideIdList;
foreach (var slideId in slideIdList.ChildElements.OfType<SlideId>())
{
//TODO:解析页面的内容
}

2.1 直接保存在slide*.xml文件的节点数据

直接保存在slide*.xml文件的文本数据只需遍历页面中的每一个paragraph对象即可,需要注意的是此处的用到的是DocumentFormat.OpenXml.Drawing.Paragraph。

 foreach (var paragraph in
slidePart.Slide.Descendants<DocumentFormat.OpenXml.Drawing.Paragraph>())
{
contentText.Length = 0;
foreach (var text in paragraph.Descendants<DocumentFormat.OpenXml.Drawing.Text>())
{
contentText.Append(text.InnerText);
}
}

2.2 以oleObject对象的形式存储在word文档中

oleObject对象在slide*.xml文件中记录形式如下图:

progId的值为“Word.Document.8”表示嵌入的对象是Office 2007以前的数据格式,值为“Word.Document.12”表示嵌入的对象是Office 2007以后的OOXML定义的数据格式。通过r:id的值获取嵌入的文件对象及其ContentType。值为 "application/vnd.openxmlformats-officedocument.wordprocessingml.document"表示嵌入的对象是word文档,值为"application/vnd.openxmlformats-officedocument.oleObject"标识嵌入的是bin文件。

Office 2007以后的OOXML定义的数据格式直接通过DocumentFormat.OpenXml解析,需要注意的是在解析word中的段落需要用DocumentFormat.OpenXml.Wordprocessing.Paragraph。

foreach (var choice in
slidePart.Slide.Descendants<DocumentFormat.OpenXml.AlternateContentChoice>())
{
foreach (var oleobject in
choice.Descendants<DocumentFormat.OpenXml.Presentation.OleObject>())
{
if (oleobject.ProgId.Value == "Word.Document.12")
{
var part = slidePart.GetPartById(oleobject.Id);
if (part.ContentType == "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
{
using (var stream = part.GetStream(FileMode.Open, FileAccess.Read))
{
using (var wordDocument = WordprocessingDocument.Open(stream, false))
{
var mainDocumentPart = wordDocument.MainDocumentPart;
var body = mainDocumentPart.Document.Body;
foreach (DocumentFormat.OpenXml.Wordprocessing.Paragraph paragraph in body.Descendants<DocumentFormat.OpenXml.Wordprocessing.Paragraph>())
{
contentText.Length = 0;
foreach (var text in
paragraph.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>())
{
contentText.Append(text.InnerText);
}
}
}
}
}
}
}
}

Office 2007以前的数据格式借助FreeSpire.Doc解析


else if (oleobject.ProgId.Value == "Word.Document.8")
{
var part = slidePart.GetPartById(oleobject.Id);
var stream = part.GetStream(FileMode.Open, FileAccess.Read);
Spire.Doc.Document doc = new Spire.Doc.Document(stream);
foreach (Spire.Doc.DocumentObject child in doc.Sections[0].Body.ChildObjects)
{
if (child is Spire.Doc.Documents.Paragraph)
paraList.Add((child as Spire.Doc.Documents.Paragraph).Text);
else if (child is Spire.Doc.Table)
{
Spire.Doc.Table table = child as Spire.Doc.Table;
foreach (Spire.Doc.TableRow row in table.Rows)
{
foreach (Spire.Doc.TableCell cell in row.Cells)
{
foreach (Spire.Doc.Documents.Paragraph paragraph in cell.Paragraphs)
{
paraList.Add(paragraph.Text);
}
}
}
}
}
stream.Dispose();
}

2.3 以oleObject对象的形式存储在bin文件中

这种情况需要通过StgOpenStorage解析oleObject对象提取word数据的文件流:

[DllImport("ole32.dll")]
private static extern int StgIsStorageFile(
[MarshalAs(UnmanagedType.LPWStr)] string pwcsName);
[DllImport("ole32.dll")]
static extern int StgOpenStorage(
[MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
IStorage pstgPriority,
STGM grfMode,
IntPtr snbExclude,
uint reserved,
out IStorage ppstgOpen);
public MemoryStream parseOleObject(string fileName)
{
MemoryStream outBuffer=default(MemoryStream);
if (StgIsStorageFile(fileName) == 0)
{
IStorage storage = null;
if (StgOpenStorage(
fileName,
null,
STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE,
IntPtr.Zero,
0,
out storage) == 0)
{
System.Runtime.InteropServices.ComTypes.STATSTG statstg;
storage.Stat(out statstg, (uint)STATFLAG.STATFLAG_DEFAULT);
IEnumSTATSTG pIEnumStatStg = null;
storage.EnumElements(0, IntPtr.Zero, 0, out pIEnumStatStg);
System.Runtime.InteropServices.ComTypes.STATSTG[] regelt = { statstg };
uint fetched = 0;
uint res = pIEnumStatStg.Next(1, regelt, out fetched);
if (res == 0)
{
while (res != 1)
{
string strNode = statstg.pwcsName;
if (strNode == "Package")
{
switch (statstg.type)
{
case (int)STGTY.STGTY_STORAGE:
{
IStorage pIChildStorage;
storage.OpenStorage(statstg.pwcsName,
null,
(uint)(STGM.READ | STGM.SHARE_EXCLUSIVE),
IntPtr.Zero,
0,
out pIChildStorage);
}
break;
case (int)STGTY.STGTY_STREAM:
{
IStream pIStream;
storage.OpenStream(statstg.pwcsName,
IntPtr.Zero,
(uint)(STGM.READ | STGM.SHARE_EXCLUSIVE),
0,
out pIStream);
outBuffer = pIStream.ReadToMemoryStream();
Marshal.FinalReleaseComObject(pIStream);
Marshal.FinalReleaseComObject(pIEnumStatStg);
Marshal.FinalReleaseComObject(storage);
return outBuffer;
}
break;
}
}
if ((res = pIEnumStatStg.Next(1, regelt, out fetched)) != 1)
{
statstg = regelt[0];
}
}
}
}
}
return outBuffer;
}

解析oleObject对象提取word数据的文件流后按照解析word对象的方式解析数据即可。


参考资料:

Office OpenXml SDK 使用 Fallback 图片显示 Ole 元素

reading-compound-documents-in-c-sharp

C# 使用openxml解析PPTX中的文本内容的更多相关文章

  1. s:textarea中的文本内容在什么时候才能被赋值给Action中的属性?

    下面是jsp程序片段: <s:form id="startForm" name ="startForm" action="/hall/hall_ ...

  2. .net获取select控件中的文本内容

    .net获取select控件中的文本内容 2009-11-28 21:19小V古 | 分类:C#/.NET | 浏览1374次 <select id="SecType" st ...

  3. 【转载】 C#往文件中追加文本内容信息

    在C#的文件相关操作中,往已有的文件中追加相关内容信息也是常有的操作,例如我们在写网站日志文件的时候,很多时候是1天的日志存放在一个txt文件中,此时就涉及到往原有文件中追加写入文本内容信息,追加文本 ...

  4. 利用java从docx文档中提取文本内容

    利用java从docx文档中提取文本内容 使用Apache的第三方jar包,地址为https://poi.apache.org/ docx文档内容如图: 目录结构: 每个文件夹的名称为日期加上来源,例 ...

  5. 使用openxml提取word中的文本和图片并转为Html

    使用openxml提取word中的文本和图片 使用 openXml 提取 word 中的 Text 和 Drawing 使用 openXml 将 word 中的文本和图片转为Html 使用 openX ...

  6. C++中关于文本内容的实用操作集合(新)(添加一些关于文件流的介绍)

    首先先给大家一个链接:http://baike.baidu.com/view/1679747.htm 主要是关于ios的使用,头文件要include<ios>,然后就可以调用下面的一些操作 ...

  7. 用python解析pdf中的文本与表格【pdfplumber的安装与使用】

    我们接触到的很多文档资料都是以pdf格式存在的,比如:论文,技术文档,标准文件,书籍等.pdf格式使得用机器从中提取信息格外困难. 为了解决这个问题,我找到了几种解决方案,最后选择了python上的p ...

  8. 【编程技巧】JAVA读取url地址中的文本内容

    应用场景:最常见的是有自已的网站,在注册广告联盟的时候.都需要下载一个文本文件来验证网站的有效性.例如淘宝.京东等都有这一过程 实现代码://读url地址的内容        public void ...

  9. 4-4 Selector有一个方法可以获取Selector中的文本内容---extract()

    ####### 例如: response.xpath('//div[@class ="entry-header"]/h1/text()').extract()

  10. Jsoup解析Html中文文档

    jsoup 简介Java 程序在解析 HTML 文档时,相信大家都接触过 htmlparser 这个开源项目,我曾经在 IBM DW 上发表过两篇关于 htmlparser 的文章,分别是:从 HTM ...

随机推荐

  1. 2022-07-20:以下go语言代码是关于json 和 context的,输出什么?A:{};B:{“a“:“b“};C:{“Context“:0};D:不确定。 package main imp

    2022-07-20:以下go语言代码是关于json 和 context的,输出什么?A:{}:B:{"a":"b"}:C:{"Context&quo ...

  2. 2021-02-18:给定一个字符串str,给定一个字符串类型的数组arr,出现的字符都是小写英文。arr每一个字符串,代表一张贴纸,你可以把单个字符剪开使用,目的是拼出str来。返回需要至少多少张贴纸可以完成这个任务。例子:str= "babac",arr = {"ba","c","abcd"}。a + ba + c 3 abcd + abcd 2 abcd+ba 2。所以返回2。

    2021-02-18:给定一个字符串str,给定一个字符串类型的数组arr,出现的字符都是小写英文.arr每一个字符串,代表一张贴纸,你可以把单个字符剪开使用,目的是拼出str来.返回需要至少多少张贴 ...

  3. AHB2APB bridge IP简介

    背景介绍 AMBA总线规范是由ARM公司提出的一种开放性的片上总线标准,它独立于处理器和工艺技术,具有高速度.低功耗等特点.AMBA规范中包括了AHB系统总线和APB外设总线. AHB主要用于高性能模 ...

  4. 去掉谷歌/新版Edge 浏览器的禁用扩展提示

    简介 你打开是谷歌/新版Edge浏览器的时候是不是总发现右上角有个提示?请禁用/停用以开发者模式运行的扩展程序?每次打开都有一个小框框,让人很烦? 接下来让我们使用 dll大法 来解决这个问题! 步骤 ...

  5. computed与watch监听同一对象的场景

    今日项目需要一个详细的权限配置,如:路由权限,页面tabs权限,操作权限:而路由权限大都知道就不赘述,而操作权限这就涉及页面中每个按钮了,这里使用VUEX进行管理 1.配置store store 中 ...

  6. 安装Visio 2013与原本的office冲突的最终解决方案

    一. 下载office visio 2013 这个直接去网上下载一个安装包解压即可 或者直接云盘下载 https://pan.baidu.com/s/1jWGFoHAjegBBvyrL1rq4DQ 提 ...

  7. Mac常用文件解压命令

    tar 解压:tar xvf fileName.tar 压缩:tar cvf fileName.tar directoryName rar 1.安装rar 下载RAR https://www.rarl ...

  8. .NET周报 【5月第3期 2023-05-21】

    国内文章 C# 实现 Linux 视频会议(源码,支持信创环境,银河麒麟,统信UOS) https://www.cnblogs.com/shawshank/p/17390248.html 信创是现阶段 ...

  9. linux 条件语句和逻辑判断

    目录 一.条件判断 二.逻辑判断 三.if和case 四.七个实验 一.条件判断 1.test测试 test [ 条件表达式 ] -e:测试目录是否存在 -d:测试是否为目录    -f:是否为文件 ...

  10. SpringBoot打包成WAR包的时候把第三方jar包打到LIB文件夹下和把第三方jar包打入到SpringBoot jar包中

    SpringBoot打包成WAR包的时候把第三方jar包打到LIB文件夹下和把第三方jar包打入到SpringBoot jar包中 转载 首先我们应该知道我们把SPRINGBOOT项目打包成WAR包和 ...