Office OpenXML -WordprocessingML 解析(一):样式

在 Office OpenXML(OOXML) WordprocessingML 文档中,样式是预定义的表格,编号,段落和字符属性的集合,能够应用于文档中的文本。下文主要了解样式的3个特性。

1. 同类样式之间的继承关系

样式可以继承于其他的同类型样式。这种继承关系是通过指定样式的basedOn元素来实现的,元素的值表示其父样式的ID。

所以,为了获得某一样式的完整属性,应该遍历其继承树直到未指定basedOn元素的样式。当同一属性在子样式和父样式中都出现时,子样式中的值会覆盖其父样式中的值。

例如,有如下两个样式:

// 标题 1
<w:style w:type="paragraph" w:styleId="1" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:name w:val="heading 1" />
  <w:basedOn w:val="a" /> // 父样式StyleId为"a"
  <w:qFormat />
  <w:pPr>
    <w:outlineLvl w:val="0" />
  </w:pPr>
  <w:rPr>
    <w:rFonts w:eastAsia="黑体" />
  </w:rPr>
</w:style>

// 正文
<w:style w:type="paragraph" w:styleId="a" w:default="1" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:name w:val="Normal" />
  <w:qFormat />
  <w:rsid w:val="002C5BB6" />
  <w:pPr>
    <w:jc w:val="center" />
  </w:pPr>
  <w:rPr>
    <w:rFonts w:eastAsia="宋体" />
  </w:rPr>
</w:style>

其中,“标题 1” 样式通过basedOn元素指定其父样式为 “正文” 样式,那么,“标题 1” 样式继承了正文中的居中对齐属性,而它的中文字体 “黑体” 覆盖了正文中的 “宋体”。最终,“标题 1” 的样式为 黑体,居中,大纲级别1级。

2. 不同样式之间的应用顺序

样式有4种类型:表格、编号、段落和字符。不同类型的样式可以应用于文档中的同一内容,每种样式按下图的顺序来应用:

上图的流程如下:

  • 首先,文档默认格式(document defaults)应用于文档中的所有 paragraph 和 run 元素;
  • 然后,表格样式属性应用于文档中每一个引用此样式的表格;
  • 接下来,编号样式属性应用于文档中的编号项;
  • 然后,段落样式的 paragraph 和 run 属性应用于每一个引用此样式的段落;
  • 再然后,字符样式的 run 属性应用于每一个引用该样式的 run;
  • 最后,应用 paragraph 和 run 元素下的属性(direct formatting)。

3. Toggle(触发器)属性

在 WordprocessingML 文档中,Bold(加粗)是 toggle 属性。如前两节所述,多种样式可以同时影响文档同一块内容的格式。当同一属性出现在一个或多个应用于某个run的样式中时,共同作用的结果和它是否是 toggle 属性有关。

如果属性不是 toggle 属性,那么属性的值应该按照前两节的规则来确定,也就是流程中最后出现的值生效。

如果属性是 toggle 属性,它的值应该是 truefalse (或着 1 或 0),那么应该遵循以下规则:

  • 如果一个 toggle 属性在内容的直接格式中有定义,那么应该使用直接格式中的值。
  • 否则,toggle 属性的值按以下方式确定:
    • 如果一个 toggle 属性出现在相同级别的不同样式中,那么应该采用按如下方式第一个出现的值(如果样式中均未出现该属性,那么该属性的值应该使用默认值):
      • 尝试从样式中读取属性值;
      • 如果样式中没有指定此属性但是指定了 basedOn 元素,那么使用 baseOn指定的父样式重复上述步骤。
      • 例如:在一个段落样式中未指定 bold 属性,但是在其父样式中指定了该属性,并且值为 true。那么该样式的 bold 属性为 true
    • 如果一个 toggle 属性出现在不同级别的多个样式中,那么它的值按照下述规则计算:
      • 如果该属性在文档默认格式中的值为 true,那么它的值就是 true
      • 反之,按照如下公式计算:
      • value = val(table) XOR val(paragraph) XOR val(character)

例如,下面这样一个文档:

在表格中,表格应用了一个样式,指定第一行加粗;在第一个单元格中,文字“1行”指定了“标题 1” 字符样式,样式设置了加粗,如下所示:
表格样式:

<w:tblStylePr w:type="firstRow">
    <w:rPr>
      <w:b />
      <w:bCs />
    </w:rPr>
  </w:tblStylePr>

"标题 1 字符" 样式:

<w:style w:type="character" w:styleId="10" w:customStyle="1" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:name w:val="标题 1 字符" />
  <w:basedOn w:val="a0" />
  <w:link w:val="1" />
  <w:uiPriority w:val="9" />
  <w:rsid w:val="00D8098D" />
  <w:rPr>
    <w:b />
    <w:bCs />
    <w:kern w:val="44" />
    <w:sz w:val="44" />
    <w:szCs w:val="44" />
  </w:rPr>
</w:style>

根据上述规则,由于 bold 是 Toggle 属性,而且出现在了不同类型的样式中,所以首先判断 bold 属性在文档默认格式中的值是否为 true:

<w:docDefaults xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:rPrDefault>
    <w:rPr>
      <w:rFonts w:asciiTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:eastAsiaTheme="minorEastAsia" w:cstheme="minorBidi" />
      <w:kern w:val="2" />
      <w:sz w:val="21" />
      <w:szCs w:val="21" />
      <w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA" />
    </w:rPr>
  </w:rPrDefault>
  <w:pPrDefault />
</w:docDefaults>

从上面可以看到,在默认值中没有指定 bold 元素,也就是说不符合第一个条件;

然后,按照公式 value = val(table) XOR val(paragraph) XOR val(character) 计算得出:

true XOR false XOR true => false

所以,最终的结果是 false, 也就是不加粗。

如果此时我们对第一个段落应用 “标题 2”段落样式,且“标题 2” 设置加粗,那么最终结果如下:

1 行 = true XOR true XOR true = true;

1 列 = true XOR true XOR false = false;

除了 Bold 外,下面这些元素也是 toggle 属性:bCs (Complex Script Bold) ,caps (Display All Characters As Capital Letters),emboss (Embossing),i (Italics),iCs (Complex Script Italics),iCs (Complex Script Italics),outline (Display Character Outline),shadow (Shadow),smallCaps (Small Caps),strike (Single Strikethrough),vanish (Hidden Text) 。

4. 参考

[1] ECMA-376-1:2016,Office Open XML File Formats — Fundamentals and Markup Language Reference,§17.7 Styles

posted @ 2023-01-28 18:11  theyangfan  阅读(1371)  评论(0编辑  收藏  举报