作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
斯捷潘Yakovenko的头像

斯捷潘Yakovenko

Stepan是一位经验丰富的软件开发人员,拥有丰富的c++工作经验, Java, JavaScript, SQL, PHP, 和c#.

专业知识

工作经验

18

分享

大约有10亿人在使用微软办公软件, 多克斯格式是办公室之间交换文档文件的最流行的事实上的标准. 它最接近的竞争对手——ODT格式——只有Open/LibreOffice和一些开源产品支持, 使它远离标准. PDF格式不是竞争对手,因为PDF不能编辑,也不包含完整的文档结构, 所以他们只能采取有限的局部变化,比如水印, 签名, 诸如此类. This is why most business 文档s are created in the 多克斯 format; there’s no good alternative to replace it.

而多克斯是一种复杂的格式, 您可能希望手动解析它,以便执行更简单的任务,如索引, 转换为TXT并进行其他小修改. 我想为您提供有关多克斯内部的足够信息,以便您不必参考ECMA规范, 巨大的5,000页手册.

理解这种格式的最佳方法是使用MSWord创建一个简单的单单词文档,并观察编辑文档如何更改底层XML. 您将遇到一些情况,多克斯在MS Word中无法正确格式化,而您不知道原因, 或者遇到不清楚如何生成所需格式的实例. 准确地看到和理解XML中正在发生的事情将有助于实现这一点.

我花了一年的时间做多克斯编辑器, CollabOffice,我想与开发者社区分享其中的一些知识. 在本文中,我将解释多克斯文件结构, 汇总分散在互联网上的信息. 这篇文章是一个巨大的中介, 复杂的ECMA规范和简单的互联网教程目前可用. 您可以在 toptal-多克斯 我的项目 github帐户.

简单的多克斯文件

多克斯文件是XML文件的ZIP归档. 如果你创建一个新的, 空白Word文档, 在里面写一个单词“Test”并解压缩它的内容, 你会看到如下的文件结构:

我们全新的测试多克斯结构.

尽管我们创建了一个简单的文档, 微软 Word中的保存过程生成了默认主题, 文档属性, 字体表, 等等......。, XML格式.

多克斯中的所有文件都是XML文件,即使是带有.rel”扩展.

首先,让我们删除未使用的东西并专注于 文档.xml,其中包含主要文本元素. 删除文件时, 确保已经从其他XML文件中删除了对它的所有关系引用. 下面是一个代码diff示例 我是如何清除对app的依赖的.XML和核心.xml. 如果您有任何未解析/丢失的引用,MSWord将认为文件损坏.

下面是我们简化的最小多克斯文档的结构(和 这是github上的项目):

我们简化的多克斯结构.

让我们从这里开始按文件分类,从上到下:

_rel /.rel

这定义了一个引用,该引用告诉MS Word在哪里查找文档内容. 在本例中,它引用 词/文档.xml:



   

_rel /文档.xml.rel

该文件定义了对嵌入在文档内容中的资源(如图像)的引用. 我们的简单文档没有嵌入资源,所以关系标签是空的:




[Content_Types].xml

[Content_Types].xml 包含有关document中媒体类型The信息. 因为我们只有文本内容,所以非常简单:



   document.xml

最后,这里是包含document文本内容The主XML. 为了清晰起见,我删除了一些名称空间声明, 但是您可以在githubProjects中找到该文件The完整版本. 在该文件中,您将发现document中The一些名称空间引用是未使用The, 但你不应该删除它们,因为MS Word需要它们.

下面是我们The简化Example:


   
       
           Test
       
       
           
           
           
           
       
   

主节点 表示文档本身, 包含段落,并嵌套其中 页面尺寸是由 .

is an attribute that you can ignore; it’s used by MS Word internals.

让我们看一个更复杂的有三个段落的文档. 在微软Word的截图中,我用相同的颜色突出显示了XML, 所以你可以看到相关性:

带有样式的复杂段落示例.

This is our example first paragraph. It's default is left aligned, 和 now I'd like to introduce some bold text , 和 also change the font style to 'Impact'. This is new paragraph. This is one more paragraph, a bit longer.

段落结构

一份简单的文件由段落组成, 段落由行(一系列具有相同字体的文本)组成, color, 等), 运行由字符(如 ). 标签内部可能有几个字符,在同一次运行中可能有几个字符.

同样,我们可以忽略 .

文本属性

基本的文本属性包括字体、大小、颜色、样式等. 大约有40个标签指定文本的外观. 正如您在我们的三段示例中看到的,每次运行都有自己的属性 ,指定 , 和大胆 .

需要注意的重要一点是,属性区分了两组字符, 正常和复杂的文字(阿拉伯语), 例如), 属性有不同的标签取决于它所影响的角色类型.

大多数普通脚本属性标记都有一个匹配的复杂脚本标记,其中添加了一个“C”,指定该属性用于复杂脚本. 例如: (斜体)成为 ,普通脚本的粗体标签, ,成为 对于复杂脚本.

Styles

在微软 Word中有一个专门用于样式的工具栏:normal, 没有间隔, 标题1, 标题2, title, 等等......。. 这些样式存储在 词/Styles.xml (注意:在我们简单示例的第一步中,我们从多克斯中删除了这个XML. 创建一个新的多克斯来查看这个).

一旦您将文本定义为样式, 您可以在段落属性标签中找到对这种样式的引用, . 这里有一个例子,我用标题1的样式定义了我的文本:


   
       
   
   
       My 标题1
   

这是Styles本身 Styles.xml:


   
   
   
   
   
   
   
   
       
       
       
       
   
   
       
       
       
       
       
       
   

Xpath指定字体为粗体,并且 指示字体颜色。. 指示MSWord对任何缺失的属性使用“Normal”样式.

财产继承

文本属性是继承的. run有它自己的属性(w: p / w: r / w:弹性分组环/ *),但它也继承段落(w: r / w: pPr / *),两者都可以从 词/Styles.xml.


 
   
   
 
 

段落和运行以默认属性开始: w:Styles/ w: docDefaults / w: rPrDefault / *w:Styles/ w: docDefaults / w: pPrDefault / *. 要获得角色属性的最终结果,你应该:

  1. 使用默认的运行/段落属性
  2. 追加运行/段落样式属性
  3. 追加本地运行/段落属性
  4. 在段落属性上附加结果运行属性

当我说“追加”B到A, 我的意思是遍历所有B的属性并重写所有A的属性, 保留所有不相交的属性.

属性中可能存在默认属性的另一个位置是 标签与 w: type =“段落”w:默认= " 1 ". 注意,运行中的字符本身从来没有默认样式,所以 实际上不会影响任何文本.

运行中的字符可以继承其段落,两者都可以继承样式.xml.

1554402290400——dbb29eef3ba6035df7ad726dfc99b2af.png)

运行中的字符可以继承其段落,两者都可以继承样式.xml.

切换性能

有些属性是“切换”属性,例如 (粗体)或 (italic); these attributes behave like an XOR operator.

这意味着如果父样式是粗体,子样式是粗体, 结果是有规律的, non-bold文本.

您必须进行大量的测试和逆向工程来正确处理toggle属性. 看一下第17段.7.ECMA-376第3条打开XML规范,以获得切换属性/的正式、详细规则

对于layouter来说,正确处理Toggle属性是最复杂的.

字体

字体遵循与其他文本属性相同的通用规则, 但字体属性默认值是在单独的主题文件中指定的, 参考下 词/ _rel /文档.xml.rel 是这样的:


根据上述参考,默认字体名称将在 词/主题/ themes1.xml在…里面 标签, themeElements /答:fontScheme: majorFont or 答:minorFont 标签.

默认字体大小为10,除非 w: docDefaults / w: rPrDefault 标签不见了,那么它是11码.

文本对齐方式

文本对齐方式由 4个标签 w:瓦尔 模式: “左”, “中心”, “正确”“两个”.

“左” is the default mode; text is started at the left of paragraph rectangle (usually the page width). (这一段是标准的左对齐.)

“中心” 可以预见的是,Mode会将所有字符居中到页面宽度内. (同样,这一段是居中对齐的例子.)

In “正确” 模式下,段落文本与右边距对齐. (注意这个文本是如何向右对齐的.)

“两个” 模式在单词之间添加额外的间距,以便行变宽并占据整个段落的宽度, 除了最后一行是左对齐的. (这一段就是一个例证.)

图片

多克斯支持两种类型的图像:内联和浮动.

内联图像与其他字符一起出现在段落中, 是用而不是用 (文本). 您可以使用以下xpath语法查找图像ID:

w:绘图/ wp:内联:图形:图形数据/图片:图片/图片:blipFill:信号/ @r:嵌入

图像ID用于查找文件中的文件名 词/ _rel /文档.xml.rel 文件,它应该指向word/media子文件夹中的gif/jpeg文件. (参见github项目的 词/ _rel /文档.xml.rel 文件,您可以在其中看到图像ID.)

浮动图像相对于周围有文字的段落放置. (这是github项目 示例文档 使用浮动图像.)

浮动图像的使用 而不是 ,所以如果你删除里面的任何文本 ,如果您不想删除图像,请小心使用锚.

内联vs. 浮动.

MS Word的图像选项将图像对齐称为“文本换行模式”。.

表的XML标记类似于HTML表标记 < w:资源描述> is the same as

, < w: tr > matches with , etc.< / w: tr >< / w:资源描述>

表本身具有表属性 ,每个列属性由 内部 . 行依次为 标记和每行应具有与中指定的相同数量的列 :


 
   
 
 
 
   left
   right
 

属性中指定表列的宽度 标签, 但是如果你没有定义它,MS Word将使用它的内部算法为最小的有效表大小找到最佳的列宽度.

单位

多克斯中的许多XML属性指定大小或距离. 虽然它们在XML中都是整数,但它们都有不同的单位,因此需要进行一些转换. 这个话题很复杂,所以我建议 Lars Corneliussen的这篇关于多克斯文件中的单元的文章. 他给出的表格很有用,但有一个小错误:英寸应该是pt/72,而不是pt*72.

这里有一个小抄:

常见的多克斯 XML单元转换
点的二十分之一
测定仪/ 20
英寸
pt/72
厘米
in*2,54
字体大小减半
pt/144
鸸鹋
in*914400
例子 11906 595.3 8,27… 21.00086… 4,135 7562088
使用这个的标签 pgSz pgMar / w:间距 w:深圳 wp:程度上,ext

实现Layouter的技巧

如果要将多克斯文件转换为PDF, 例如), 在画布上画出来, 或者计算页数, 你必须实现一个布局器. layouter是一种从多克斯文件中计算字符位置的算法.

这是一个复杂的任务,如果你需要100%的保真渲染. 实现一个好的布局所需的时间是以人年为单位来衡量的, 但如果你只需要一个简单的, 一个有限, 这可以相对较快地完成.

布局填充父矩形,父矩形通常是页面的一个矩形. 它一个接一个地添加单词. 当当前行溢出时,它开始一个新的行. 如果段落对于父矩形来说太高,它将被换行到下一页.

这里有一些重要的事情要记住,如果你决定实现一个布局:

  • 布局应该注意文本对齐和文本浮动在图像上
  • 它应该能够处理嵌套对象,比如嵌套表
  • 如果您想为此类映像提供完整的支持, 你必须实现一个至少有两个通道的布局, 第一步收集浮动图像的位置,第二步用文本字符填充空白区域.
  • 注意缩进和间隔. 每个段落的前后都有空格,这些数字由 w:间距 标签. 垂直间距由 w:后w:之前 标签. 注意,行间距由 w:行但这条线的长度可能与人们所期望的不同. 要得到行大小,取当前字体高度,乘以 w:行 然后除以12.
  • 多克斯文件不包含关于分页的信息. 除非您计算每行需要多少空间以确定页数,否则您将无法找到文档中的页数. 如果你需要找到页面上每个字符的精确坐标, 一定要考虑到所有的间距, 缩进和尺寸.
  • 如果您实现了一个全功能的多克斯布局器来处理表, 请注意表跨越多个页面时的特殊情况. 导致页面溢出的单元格也会影响其他单元格.
  • 创建计算表列宽度的最佳算法是一个具有挑战性的数学问题,而文字处理器和布局器通常使用一些次优实现. 我建议使用 W3C HTML算法 表文档作为第一个近似. 我没有找到MS Word使用的算法的描述, 随着时间的推移,微软对算法进行了微调,所以不同版本的Word可能会略有不同.

如果有不清楚The地方:对XML进行逆向Engineering!

当这个或那个XMLTags在MS Word中The工作方式不明显时, 有两种主要方法可以解决这个问题:

  • 逐步创建所需The内容. 从一个简单TheDOCX文件开始. 将每个步骤保存到自己The文件中,如 1.DOCX, 2.DOCX, for example. 解压缩它们中The每一个,并使用可视化diffTools进行文件夹比较,以查看更改后出现哪些标记. (对于商业选项,请尝试Araxis Merge,或者免费选项WinMerge.)

  • 如果您生成TheDOCX文件MS Word不喜欢,请向后工作. 一步一步地简化XML. 在某些时候,你会知道MS Word发现哪些更改是不正确The.

多克斯非常复杂,不是吗?

很复杂, 微软的许可证禁止在服务器端使用Word来处理多克斯——这对商业产品来说是相当标准的. 然而,微软已经提供了 XSLT文件 来处理大多数多克斯标签,但它不会给你100%甚至99%的保真度. 不支持图像上的文本换行等处理, 但您将能够支持大多数文档. (如果您不需要复杂性,请考虑使用 减价 作为一种选择.)

如果你有足够的预算(没有免费的多克斯渲染引擎), 您可能希望使用Aspose或多克斯4j等商业产品. 最流行的免费解决方案是LibreOffice,用于在多克斯和其他格式之间进行转换, 包括PDF. 不幸的是, LibreOffice在转换过程中包含许多小错误, 因为这是一个复杂的, 开源c++产品, 修复保真度问题是缓慢而困难的.

另外, 如果您发现多克斯布局太复杂而无法自己实现, 您还可以将其转换为HTML并使用浏览器呈现它. 你也可以考虑其中之一 ToptalThe自由XMLDevelopers.

多克斯参考资料进一步阅读

就这一主题咨询作者或专家.
预约电话
斯捷潘Yakovenko的头像
斯捷潘Yakovenko

位于 新西伯利亚,俄罗斯新西伯利亚州

成员自 2016年1月8日

作者简介

Stepan是一位经验丰富的软件开发人员,拥有丰富的c++工作经验, Java, JavaScript, SQL, PHP, 和c#.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

专业知识

工作经验

18

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.