Office 文件解析入门

Office 文件解析入门

概述 - Office 解析相关协议

这里所讲的 Office 文件指的是微软 Office2007 及以后的 PPT/EXCEL/WORD 等文件格式,因为 Office2007 以前的文件是用二进制格式定义的,不在本文的讨论内容中。

Office2007 以后的文件格式属于 OOXML 文件格式,OOXML 是基于 zip+xml 定义的。

OOXML 全称 Office Open XML File Formats,最初是由 ECMA-376 定义的,它目前已经到第六版。后来 ISO/IEC 29500 也开始掺和OOXML格式的定义,不过可以认为从 ECMA-376 的第2版开始,这两个标准是一样的。目前最新的 OOXML 标准是在 2016 年发布的 ECMA-376 5th edition 或者 ISO/IEC 29500:2016

微软的 Office 实现了OOXML格式,但不是全部,微软在 这篇文章 中描述了其对标准的支持情况。

OOXML = OPC + *ML ,下面会分别介绍 OPC*ML

由于 EMCA 文档可以免费在网上下载的,而 ISO 文档需要付费才能获取,因此下文的内容都是基于 ECMA-376 文档。

OPC - Open Package Convention

关于 OPC 的详细内容请参考 ECMA-376,Fourth Edition,Part 2

OPC 中文名开放打包协定,是一种基于 zip+xml 定义的文件存储格式。一个 OPC 文件(不管其文件后缀是什么)本质上就是一个 zip 文件,你可以用任何常见的解压软件进行解压,解压后你看到的那些文件的组织结构,就是以 OPC 定义的方式存储的。下图是一个PPTX文件解压后的目录结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qDbyGMsj-1601820950235)(./ppt-decompress.png)]

OPC 中有3个重要的概念要理解:Part , Relationship , ContentTypes

Part

Part 可以简单理解为 zip 中的文件,每一个文件都是一个 Part ,它可以是任何格式,比如图片,xml文件等。在 Office 文件中,各种 Markup Language 定义的内容就作为 XML 存储在 Part 中。

Relationship

Relationship 是一种特殊的 Part ,它描述了各 Part 之间的依赖关系。根据OPC协议的规定,所有的 Relationship 都必须存储在名为 _rels 的文件夹中,并且所有 Relationship 的文件名都必须以 .rels 为后缀。

每一个 Part 根据业务需求都可以有对应的 Relationship 文件,比如在 PPTX 文件中,有一个 Part 为 /ppt/presentation.xml ,它对应的 Relationship 文件(只能)为/ppt/_rels/presentation.xml.rels ,不能是任何其它名字或者位置的文件。下面是一个 PPTX 文件中的 presentation.xml.rels 文件:

<?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/slide" Target="slides/slide2.xml"/>
    <Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableStyles" Target="tableStyles.xml"/>
    <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/>
    <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" Target="slideMasters/slideMaster1.xml"/>
    <Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
    <Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/viewProps" Target="viewProps.xml"/>
    <Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/presProps" Target="presProps.xml"/>
</Relationships>

Relationship 文件的根节点是 RelationShips, 它是 Relationship 节点的集合,每一个 Relationship 节点都代表一个依赖关系。它的各个属性的意义如下:

属性名是否必须说明
Id唯一标识符,在当前文件中是唯一的,不同文件中可以重复
TypeTarget 的文件类型
Target目标 Part 的路径,可以用相对路径也可以用绝对路径
TargetMode目标的类型,值可以是 Internal 或者 External (默认是Internal),表示 Target 是OPC文件内部的还是外部的

ContentTypes

ContentTypes 在zip压缩包的根目录下,文件名为 [Content_Types].xml ,它记录了该OPC文件中除了他自己以外的所有文件的类型。下面是一个PPTX文件的 ContentTypes 文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
    <Default Extension="jpeg" ContentType="image/jpeg"/>
    <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
    <Default Extension="xml" ContentType="application/xml"/>
    <Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/>
    <Override PartName="/ppt/slideMasters/slideMaster1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"/>
    <Override PartName="/ppt/slides/slide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>
    <Override PartName="/ppt/slides/slide2.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>
    <Override PartName="/ppt/presProps.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presProps+xml"/>
    <Override PartName="/ppt/viewProps.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml"/>
    <Override PartName="/ppt/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/>
    <Override PartName="/ppt/tableStyles.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml"/>
    <Override PartName="/ppt/slideLayouts/slideLayout1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/>
    <Override PartName="/ppt/slideLayouts/slideLayout2.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/>
    <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
    <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
</Types>

其中有两种标签 DefaultOverride , Default 指明了拥有文件后缀名和文件类型的对应关系, Override 指明了某一个文件的文件类型。

比如:<Default Extension="jpeg" ContentType="image/jpeg"/> 的意思是后缀为 jpeg 的文件都是 image/jpeg 类型的文件,因此在OPC中不建议根据文件后缀名来判断一个文件的类型,而应该根据 ContentTypes 文件中记录的信息来判断文件类型。

*ML (* Markup Language)

关于各种 ML 语言的详细信息请参考 ECMA-376,Fifth Edition,Part 1

Markup Language (ML) 译为 标记语言,是一种用 XML 来描述数据的"语言",比如:

*ML全名说明
PMLPresentation Markup LanguagePPT 中各种数据的描述
WMLWordprocessing Markup LanguageWord 中数据的描述
SMLSpreadsheet Markup LanguageExcel 中数据的描述
DMLDrawing Markup LanguageOffice 所有格式中都可以使用,用来描述矢量图形,图表等
SharedMLShared Markup Language描述了文档属性,音视频,图片,文档主题等内容,它被所有Office文件使用

比如之前提到的 presentation.xml 文件,它的文件内容就是在 PML 中定义的。具体信息可以查看 ECMA-376,Fifth Edition,Part 1。但是,ECMA-376 太长了,还没看就头疼,怎么办。

首先了解一下在 EMCA-376 中用来定义各种 ML 语言的 XSD

XSD - XML Schema Definition 或者 XML Schema

XSD 类似 DTD,它们有相似的作用。在 ECMA-376 中,所有的 Markup Language 都是 XML 格式的,而这些 XML 的具体节点内容,都是用 XSD 来定义的,所以我们要对它有一定的了解:

XML Schema(XSD) 的作用:

  • 定义可出现在文档中的元素
  • 定义可出现在文档中的属性
  • 定义哪个元素是子元素
  • 定义子元素的次序
  • 定义子元素的数目
  • 定义元素是否为空,或者是否可包含文本
  • 定义元素和属性的数据类型
  • 定义元素和属性的默认值以及固定值
    (可以在 这里 找到 XSD 的详细内容。)

XSD 中,有两个比较重要的概念:Simple Type(简单类型)Complex Type(复杂类型)

名称说明
Simple Type Element简单类型元素,指那些仅包含文本的元素。它不会包含任何其他的元素或属性。 比如:<id>123</id>,这里元素 id 就是简单类型元素。
Complex Type Element复杂类型元素,指那些可以包含其他任意元素或者属性的元素。

比如在 PML 中定义 页面大小(SlideSize) 这个元素(节点)的 XSD 如下:

<xsd:complexType name="CT_SlideSize"> 
    <xsd:attribute name="cx" type="ST_SlideSizeCoordinate" use="required"/> 
    <xsd:attribute name="cy" type="ST_SlideSizeCoordinate" use="required"/> 
    <xsd:attribute name="type" type="ST_SlideSizeType" use="optional" default="custom"/> 
</xsd:complexType>

可以看出 CT_SlideSize 是个 complexType(复杂类型) 的元素,并且它有三个 attribute(属性) ,分别是 cx , cytype,根据它们 type 的前缀 ST_ ,可以看出这三个属性都是简单类型的,并且是 required 的。如果你明白了这里的描述,再去看 ECMA-376 中各种 ML 语言的定义应该会简单一点。

PS: 在看 ECMA-376 的时候可以先只看前 16 章的内容,只有160页左右,如果只算内容的话更少,后面的将近 5000 页都可以解析哪部分就去看哪部分就行了。言外之意就是,其实也没有想象中的那么唬人。JUST DO IT !

PPTX 解析的基本流程

这里以 PPTX 的解析为例,其它的 WORD 或者 EXCEL 可以触类旁通。

基本流程如下:

  1. 读取 /[Content_Types].xml 文件,获取到所有文件的类型;
    这部分需要了解 OPC 中关于 ContentTypes 的内容。
  2. 读取 /_rels/.rels 这个所谓的 Package Relationship 文件,获取 presentation.xml 文件的位置,比如 /ppt/presentation.xml
    这部分需要了解 OPC 中关于 Relationship 的内容以及 PML 的基本内容。
  3. 读取 /ppt/presentation.xml 文件以及其关联的 Relationship 文件 /ppt/_rels/presentation.xml.rels,得到该PPT所有页面文件的存储位置,比如 /ppt/slides/slide1.xml,以及 slideMaster(母版)文件的存储位置,比如 /ppt/slideMasters/slideMaster1.xml,以及 slideLayout(板式)等相关文件的存储位置;
    这部分需要了解 PML 中关于 Presentation 的定义,也就是 PML 的 XSD 中定义的 CT_Presentation 类型。这个时候可以去详细的阅读 Presentation 章节的详细信息了。
  4. 读取 /ppt/slides/slide1.xml 文件内容以及其关联的 Relationship /ppt/slides/_rels/slide1.xml.rels,可以得到该页面的所有元素信息;
    这部分要完整解析就需要了解所有 PML、DML、SharedML 中的内容了。

不知道看到这里你还要不要自己解析啊?如果不愿意了,那大名鼎鼎的 POI 也许可以救你于水深火热。

POI/NPOI

POI 是 Apache 的项目,这里 是它的官网(NPOI 是 POI 的 .NET 版本)。背景知识我就不介绍了,这里摘自维基百科对它模块划分的介绍,可以在自己解析的时候参考:

POIFS (Poor Obfuscation Implementation File System) – This component reads and writes Microsoft's OLE 2 Compound document format. Since all Microsoft Office files are OLE 2 files, this component is the basic building block of all the other POI elements. POIFS can therefore be used to read a wider variety of files, beyond those whose explicit decoders are already written in POI.(也就是OPC模块)
HSSF (Horrible SpreadSheet Format) – reads and writes Microsoft Excel (XLS) format files. It can read files written by Excel 97 onwards; this file format is known as the BIFF 8 format. As the Excel file format is complex and contains a number of tricky characteristics, some of the more advanced features cannot be read.()
XSSF (XML SpreadSheet Format) – reads and writes Office Open XML (XLSX) format files. Similar feature set to HSSF, but for Office Open XML files.
HPSF (Horrible Property Set Format) – reads "Document Summary" information from Microsoft Office files. This is essentially the information that one can see by using the File|Properties menu item within an Office application.
HWPF (Horrible Word Processor Format) – aims to read and write Microsoft Word 97 (DOC) format files. This component is in initial stages of development.
XWPF (XML Word Processor Format) – similar feature set to HWPF, but for Office Open XML files.
HSLF (Horrible Slide Layout Format) – a pure Java implementation for Microsoft PowerPoint files. This provides the ability to read, create and edit presentations (though some things are easier to do than others)
HDGF (Horrible DiaGram Format) – an initial pure Java implementation for Microsoft Visio binary files. It provides an ability to read the low level contents of the files.
HPBF (Horrible PuBlisher Format) – a pure Java implementation for Microsoft Publisher files.
HSMF (Horrible Stupid Mail Format[7][better source needed]) – a pure Java implementation for Microsoft Outlook MSG files.[8]
DDF (Dreadful Drawing Format) – a package for decoding the Microsoft Office Drawing format.

需要注意的是 POI 貌似对 PPT 的支持比较弱?

最后

你应该只是需要部分解析 Office 格式吧?难道你想过完全解析么?太可怕了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值