Office 文档解析 文档格式和协议
本文讨论的 Office 文档指的是 Office 2007 及以后的 PPTX 和 xlsx 等格式的文件。在 Office 2007 之前使用的不公开标准的二进制格式定义。在 Office 2007 之后的文档格式使用 OOXML 国际标准定义,本文将告诉大家这个标准的协议和格式
在 Office 2007 之后的 Office 文档格式采用的是 OOXML 标准格式。那什么是 OOXML 标准?这里的 OOXML 的全称是 Office Open XML File Formats 或被称为 OpenXML 格式,这是一个基于 zip+xml 定义的文档格式。这个标准最初是由 ECMA-376 定义的,后来 ISO/IEC 29500 也开始掺和 OOXML 格式的定义,不过可以认为从 ECMA-376 的第2版开始,这两个标准是一样的
微软的 Office 实现了 OOXML 格式,但仅实现其中一部分,详细描述请看 官方文档
在 OOXML 格式里面,如上文所说是基于 zip+xml 定义的,这里的 Zip 提供文件的支持,而 xml 提供内容的支持。不过 OOXML 使用的 zip 也是有规范的,这里使用 OPC (Open Package Convention) 中文名叫 开放打包协定
作为文件存储格式。当然,这并非说 OPC 使用特殊的 zip 格式,而是 OPC 规定了文件存放的存储格式,然后将这些文件使用 zip 打包为一个文件。因此 一个 OPC 文件(不管其文件后缀是什么)本质上就是一个 zip 文件,你可以用任何常见的解压软件进行解压,解压后你看到的那些文件的组织结构,就是以 OPC 定义的方式存储的
在 ECMA-376,Fourth Edition,Part 2 详细定义了 OPC 开放打包协定。在 OPC 里面有三个重要的概念,分别是 Part 和 Relationship 和 ContentTypes 这三个
什么是 Part
简单理解就是 zip 的文件,每一个文件都是一个 Part 可以是任何格式,比如图片和xml文件等。在 Office 文件中,各种 Markup Language 定义的内容就作为 XML 存储在 Part 中
而 Relationship 是一种特殊的 Part 文件,它描述了各 Part 之间的依赖关系。根据OPC协议的规定,所有的 Relationship 都必须存储在名为 _rels
的文件夹中,并且所有 Relationship 的文件名都必须以 .rels 为后缀。每个 Part 可以根据自身的业务需求有一个对应的 Relationship 文件,这个对应的 Relationship 文件必须存放在这个 Part 文件所在文件夹的 _rels
文件夹里面,同时要求使用 Part 文件加上 .rels
后缀,不能使用其他名字
如有一个 PPTX 的页面是 pptslidesslide1.xml
此时这个页面的 Relationship 必须是 pptslides_relsslide1.xml.rels
文件,不能使用其他命名
最后一个 ContentTypes 相信小伙伴也不陌生,这是放在zip压缩包的根目录下的 [Content_Types].xml
文件,这是基本上每个 NuGet 包都会带的内容(不认识NuGet的小伙伴请点击右上角关闭按钮,因为你不要妄想玩转Office解析了),在 [Content_Types].xml
文件记录了该 OPC 压缩文件中除了他自己以外的所有文件的类型。这个文件作用是解决后缀名判断问题,在 OPC 定义里面不建议使用后缀名判断文件类型,而是根据 [Content_Types].xml
文件记录判断文件类型
讲完了文件存储方式,剩下的就是 XML 表示文件内容。在 OOXML 格式里面,可以认为是 OPC + *ML
的组合,这里的 *ML
表示的是各个标记语言,如 PML(Presentation Markup Language PPT 中各种数据的描述)等,这部分定义可以在 ECMA-376,Fifth Edition,Part 1 找到
解析 Office 文档用的比较多的包含 PML (Presentation Markup Language pptx, PPT 中各种数据的描述)
和 WML (Wordprocessing Markup Language docx, Word 中数据的描述)
和 SML (Spreadsheet Markup Language xlsx, Excel 中数据的描述)
和 DML(Drawing Markup Language, Office 所有格式中都可以使用,用来描述矢量图形,图表等)
和 SharedML(Shared Markup Language, 描述了文档属性,音视频,图片,文档主题等内容,它被所有Office文件使用)
等
这将会对应在 OpenXML SDK 的各个命名空间里面
OfficeTalk: Essentials of the Open Packaging Conventions
更多请看 Office 使用 OpenXML SDK 解析文档博客目录
本文会经常更新,请阅读原文: https://blog.lindexi.com/post/Office-%E6%96%87%E6%A1%A3%E8%A7%A3%E6%9E%90-%E6%96%87%E6%A1%A3%E6%A0%BC%E5%BC%8F%E5%92%8C%E5%8D%8F%E8%AE%AE.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
- 2017 Multi-University Training Contest - Team 9 1004&&HDU 6164 Dying Light【数学+模拟】
- Python3选择排序
- 【DeepMind 公开课-深度强化学习教程代码实战01】迭代法评估4*4方格世界下的随机策略
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861C Did yo
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861B Which
- 信用卡安全问题:被用户忽视的识别码
- Python3快速排序
- Python3插入排序
- Python3冒泡排序
- Python Selenium设计模式-POM
- 【Python学习笔记之一】Python关键字及其总结
- 前后端分离了,然后呢?
- 【Python学习笔记之二】浅谈Python的yield用法
- LINUX中常用操作命令
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [AWR报告]Latch Hit %
- [Python运维]Python3.6的安装
- [Python运维]cx_Oracle模块的安装
- C#中抽象类与抽象方法的作用与实例
- C++ 基础扫盲(1)
- [Python运维]使用cx_Oracle连接Oracle(高级篇)
- [Python运维]使用Python发送邮件
- [Python运维]自动化监控Oracle表空间并发送报警
- [Python运维]自动化监控多个Oracle表空间
- c# 动态生成控件
- C# 10分钟完成百度人脸识别——入门篇
- C#开启线程的四种方式
- C++入门实例:创建工程、opencv引用及简单实例
- C#实例:datagridview单元格合并
- C# 封装实例