前言

本文讨论的仅针对微软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-12-23:portainer是docker的web可视化工具。如果根据docker部署去写yaml,默认local是k8s,而不是docker,这不符合需求,需要修改yaml。请问部署在

    2022-12-23:portainer是docker的web可视化工具.如果根据docker部署去写yaml,默认local是k8s,而不是docker,这不符合需求,需要修改yaml.请问部署在 ...

  2. ToolStrip1

    Private Sub ToolStrip1_ItemClicked(sender As Object, e As ToolStripItemClickedEventArgs) Handles Too ...

  3. Javascript 常见的循环方式总结

    本文地址: https://www.cnblogs.com/zichliang/p/17412968.html 在Javascript中有很多种循环方式.有多种循环方式可以用来遍历数组.对象.以及执行 ...

  4. 【python基础】日常知识点整理

    [三种方法调用] 1. 类中的方法区分为普通方法(self),静态方法(@staticMenthod),类方法@classMenthod,隐式参数(cls) <1> 普通方法:第一个参数 ...

  5. Java的Object类的方法

    Java的Object类是所有类的根类,它提供了一些通用的方法.下面是一些常用的Object类方法: 1. equals(Object obj):判断当前对象是否与给定对象相等.默认情况下,equal ...

  6. vulnhub_jangow

    来源 vulnhub:https://www.vulnhub.com/entry/jangow-101,754/ 描述 难度:简单 这在 VirtualBox 而不是 VMware 上效果更好 我这里 ...

  7. 【理论积累】Python中的Pandas库【一】

    Pandas库介绍 Pandas 是一个用于数据分析的 Python 第三方库,能够处理和分析不同格式的数据,例如:CSV.Excel.SQL 数据库等.Pandas 提供了两种数据结构,分别为 Se ...

  8. C++面试八股文:了解auto关键字吗?

    某日二师兄参加XXX科技公司的C++工程师开发岗位第15面: 面试官:了解auto关键字吗? 二师兄:嗯,了解一些(我很熟悉). 面试官:说一说auto的用法吧? 二师兄:auto主要是为了编译器进行 ...

  9. @Target元注解的使用

    @Target注解标记另外的注解用于限制此注解可以应用哪种Java元素类型.先看Java SE 8中@Target是如何声明的: package java.lang.annotation; publi ...

  10. 第四章 VIVIM编辑器

    1. 是什么 ‍ VI 是 Unix 操作系统和类 Unix 操作系统中最通用的文本编辑器. ‍ VIM 编辑器是从 VI 发展出来的一个性能更强大的文本编辑器. ‍ 2. 一般模式 ‍ 以 vi/v ...