首发于 从零写个Office

从零写个Office(二):Office Open XML概述

ECMA-376指定了一系列的XML模式( XML schemas ),这些模式定义了诸如文字处理程序、电子表格、演示文档以及文档包所用的词汇表,也就是Office Open XML。

一、内容概述

在ECMA-376标准中主要包含下面几类

1. 标准W3C XML模式

XSD在ECMA-376-Fifteh-Edition-Part-1 [1] 中的 OfficeOpenXML-XMLSchema-Strict.zip OfficeOpenXML-RELAXNG-Strict.zip 中。

2. XML语意描述

也就是文字处理(WordprocessingML)、电子表格(SpreadsheetML)、演示文档(PresentationML)、图像(DrawingML)。

3. 附加约束

(暂未使用)

二、包

Office Open XML文档是由一系列相互关联的部分组成的一个包(Package),这个包(Package)是一个普通的ZIP文件,其中包含了包的类型描述( [Content_Types.xml] )、关联关系( .rels document.xml.rels )以及嵌套在文档中的内容、样式、信息、图片、视频、字体...之类的小块(Parts)

三、WordprocessingML

1. 段落

Word文档一般会有一块内容区,内容区中包含了段落、图片、表格等,每个段落由文本组成,这些文本、段落、图片、表格等我们可以通过工具栏进行样式的设置,比如粗体的文字、黄色边框的图片,而这些都是通过WordprocessingML来定义的。

如果有网页开发经验就很容易一下子联想到网页和HTML以及CSS的关系,事实上WordprocessingML与HTML确实如出一辙,只是标签存在较大的差异。

把上一节中 document.xml 拿出来看一下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex wp14">
    <w:body>
        <w:p w14:paraId="396385E8" w14:textId="6BF766E2" w:rsidR="00947F74" w:rsidRDefault="006640DB">
                <w:rPr>
                    <w:rFonts w:hint="eastAsia" />
                </w:rPr>
                <w:t>这是一段文本</w:t>
                <w:t xml:space="preserve"></w:t>
        <w:sectPr w:rsidR="00947F74">
            <w:pgSz w:w="11906" w:h="16838" />
            <w:pgMar w:top="1440" w:right="1800" w:bottom="1440" w:left="1800" w:header="851" w:footer="992" w:gutter="0" />
            <w:cols w:space="425" />
            <w:docGrid w:type="lines" w:linePitch="312" />
        </w:sectPr>
    </w:body>
</w:document>

WordproessingML包的文档处理部分用 w:document 包裹,其中 w:body 指定「身体」区域, w:p 是一个段落, w:r 是段落中的文本块, w:t 则指定了文本内容,而 w:rPr 更像是一块样式。

将这段代码简化后,与 HTML进行对比:

2. 章节

WoreprocessingML文档通过章节(section)来组织,同样有点类似HTML中的 div ,不过由于WordprocessingML在文档的每页使用section布局,这也使得section可以有自己的页眉页脚。

3. 样式

像HTML的CSS样式表一样,WordprocessingML也会通过一些属性来改变内容的样式,之后通过「关系表」(relationship)与内容的各部分关联起来,有点像HTML外联样式表的做法。

通过观察上节中 styles.xml 文件可以发现一些端倪,下面是 styles.xml 的一段代码片段,还是能看到一些CSS的影子。如果做过Android开发,这种XML定义样式的方式则更是烂若披掌:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex">
    <!--//.......-->
    <w:style w:type="paragraph" w:default="1" w:styleId="a">
        <w:name w:val="Normal" />
        <w:qFormat />
        <w:pPr>
            <w:widowControl w:val="0" />
            <w:jc w:val="both" />
        </w:pPr>
    </w:style>
    <w:style w:type="character" w:default="1" w:styleId="a0">
        <w:name w:val="Default Paragraph Font" />
        <w:uiPriority w:val="1" />
        <w:semiHidden />
        <w:unhideWhenUsed />
    </w:style>
    <w:style w:type="table" w:default="1" w:styleId="a1">
        <w:name w:val="Normal Table" />
        <w:uiPriority w:val="99" />
        <w:semiHidden />
        <w:unhideWhenUsed />
        <w:tblPr>
            <w:tblInd w:w="0" w:type="dxa" />
            <w:tblCellMar>
                <w:top w:w="0" w:type="dxa" />
                <w:left w:w="108" w:type="dxa" />
                <w:bottom w:w="0" w:type="dxa" />
                <w:right w:w="108" w:type="dxa" />
            </w:tblCellMar>
        </w:tblPr>
    </w:style>
    <w:style w:type="numbering" w:default="1" w:styleId="a2">
        <w:name w:val="No List" />