在 Open XML WordprocessingML 中使用编号列表

**摘要:**了解 Open XML 中的列表。Word 2010 文档经常包含编号列表和点符列表。WordprocessingML 的这一领域当然复杂。编号列表和点符列表包含许多功能,每项功能都由一组不同用户使用。

上次修改时间: 2012年1月3日

适用范围: Office 2010 | Open XML | Visual Studio Tools for Microsoft Office | Word 2007 | Word 2010

本文内容
概述
简单编号列表标记
简单点符列表标记
多级列表标记
链接到样式的编号标记
用新的编号格式替代多级列表中的编号格式
替代多级列表中的编号格式,并创建多级列表格式
处理 w:startOverride 元素
定义列表样式
列表项后缀的备选项
处理 w:lvlRestart 元素
处理 w:isLgl 元素
组合列表项文本的算法
结论
其他资源

**发布时间:**2010 年 3 月

供稿人:Eric White(该链接可能指向英文页面), Microsoft Corporation

目录

  • 概述

  • 简单编号列表标记

  • 简单点符列表标记

  • 多级列表标记

  • 链接到样式的编号标记

  • 用新的编号格式替代多级列表中的编号格式

  • 替代多级列表中的编号格式,并创建多级列表格式

  • 处理 w:startOverride 元素

  • 定义列表样式

  • 列表项后缀的备选项

  • 处理 w:lvlRestart 元素

  • 处理 w:isLgl 元素

  • 组合列表项文本的算法

概述

实施从 Open XML 字处理文档到 HTML 的转换时,其中一个值得关注的问题是如何准确转换编号列表和点符列表。您必须编写特定代码来处理它们,因为它们会影响文档中包含的文本,但是该文本并不直接位于标记中。如果您要准确地提取文档的文本,则必须处理一些元素和属性来组合正确文本。

备注

本文同时适用于 Microsoft Word 2010 和 Microsoft Office Word 2007。

点符列表和编号列表很复杂,这也是很正常的。编号列表和点符列表具有许多功能,每项功能都由一组不同的用户使用。这些功能由标记中的元素表示。不过,您没有必要注意所有元素。标记的某些方面之所以存在只是为了影响用户界面,当您确定编号项或点符项的文本表示形式时,则不必注意那些元素。本文只介绍您在处理编号项和点符项时必须了解的一些基本要素。

谈论编号标记最简单的方法是将标记与 Word 的用户界面关联。您只须关心可以通过以下三个按钮进行的文档修改:

图 1. 编号列表的工具栏按钮

编号按钮

WordprocessingML 编号标记有相当多的间接寻址。标记中的这种间接寻址有三种模式:

  1. 简单编号列表或点符列表的直接编号

  2. 基于样式的编号,即标题 1 在第一缩进级别,标题 2 在第二缩进级别。

  3. 命名的编号样式

本文分别探讨这些模式。

简单编号列表标记

下图显示创建简单编号列表时生成的标记。

图 2. 创建简单编号列表

创建简单的点符列表

为准确讨论标记,我们必须区分编号列表或点符列表的两个方面。对于每个编号项或点符项,都有两个组成部分:列表项和段落文本。

图 3. 点符列表项

列表项 - 项目符号

我们必须区分这些项目,因为列表项是我们需要为每个段落组合的内容。此外,列表项还有单独的格式设置标记。编号列表也存在这种区别。

图 4. 编号列表项

列表项 - 文本

下图显示简单编号列表或点符列表的间接寻址。

图 5. 简单编号列表或点符列表的间接寻址

简单编号间接寻址

接下来,探讨以下简单编号列表的标记。

图 6. 简单编号列表

简单编号列表

主文档部件中的标记如下所示。

<w:p>
  <w:pPr>
    <w:pStyle w:val="ListParagraph"/>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="1"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>Paragraph one.</w:t>
  </w:r>
</w:p>

w:numPr 元素包含我们所关心的编号元素。w:ilvl 元素是一个从零开始的数字,指示缩进级别。编号项位于最低缩进级别,以便 w:ilvl 的值为零。w:numId 元素是编入 w:num 元素的索引,位于编号部件中。

重要说明重要说明

w:numId 可以包含 0 值 ,这是一个特殊值,指示已从此级别的样式层次结构中删除编号。处理此标记时,如果 w:val='0',则段落不含列表项。

编号部件标记如下所示。

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<w:numbering xmlns:w="https://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:abstractNum w:abstractNumId="0">
    <!-- These affect the user interface. We can ignore them. -->
    <w:nsid w:val="5FE17486"/>
    <w:multiLevelType w:val="hybridMultilevel"/>
    <w:tmpl w:val="1084E0BA"/>
    <w:lvl w:ilvl="0"
           w:tplc="0409000F">
      <w:start w:val="1"/>
      <w:numFmt w:val="decimal"/>
      <w:lvlText w:val="%1."/>
      <w:lvlJc w:val="left"/>
      <w:pPr>
        <w:ind w:left="720"
               w:hanging="360"/>
      </w:pPr>
    </w:lvl>
    <w:lvl w:ilvl="1"
           w:tplc="04090019"
           w:tentative="1">
      <w:start w:val="1"/>
      <w:numFmt w:val="lowerLetter"/>
      <w:lvlText w:val="%2."/>
      <w:lvlJc w:val="left"/>
      <w:pPr>
        <w:ind w:left="1440"
               w:hanging="360"/>
      </w:pPr>
    </w:lvl>
    <!-- a number of other w:lvl elements elided -->
  </w:abstractNum>
  <w:num w:numId="1">
    <w:abstractNumId w:val="0"/>
  </w:num>
</w:numbering>

主文档部件中 w:numPr 元素中的索引引用 w:num 元素。在本例中,该元素包含单个元素,即 w:abstractNumId,它引用出现在它前面的 w:abstractNum 元素。w:abstractNum 元素包含设置列表项格式所需的信息。请注意,w:abstractNum 元素不包含段落的格式信息(缩进信息除外,该信息同时涉及列表项和段落)。段落本身的格式与往常一样存储在主文档部件和样式部件中。有三个元素(w:nsid 元素、w:multiLevelType 元素和 w:tmpl 元素)只影响字处理应用程序中的用户界面,您可以忽略它们。

备注

本文的其余部分从标记列表中去除了这些元素。

w:lvl 元素和 w:lvl 子元素定义列表项的每个缩进级别的格式。同时还存在其他 w:lvl 元素(已从列表中删除),用于定义第二级和更高级别上每个级别的列表项格式。w:lvl 元素的 w:tplc 属性和 w:tentative 属性的存在只是为了用户界面。我会从其他列表中删除它们。

提示

从 w:num 元素到 w:abstractNum 元素的间接寻址允许使用替代列表项格式的标记。下文中将会讨论此标记。

您真正需要关注的元素是 w:lvl 元素的子元素:w:start 元素、w:numFmt 元素、w:lvlText 元素、w:lvlJc 元素和复杂元素 w:pPr。

w:start 元素指定缩进级别的起始编号。您是从 0、1 还是其他数字开始计数?不允许使用负数(而且这样做也没有多大意义)。

在本例中,w:numFmt 元素指示文档在列表项中将一个十进制数用作缩进级别 0,将一个小写字母用作缩进级别 1。该元素有相当多的选项:

  • 点符

  • 十进制数 (1, 2, 3)

  • 零加十进制数 (01, 02, 03)

  • 大写罗马数字 (I, II, III)

  • 小写罗马数字 (i, ii, iii)

  • 大写字母 (A, B, C)

  • 小写字母 (a, b, c)

  • 序数 (1st, 2nd, 3rd)

  • 基数字 (One, Two Three)

  • 序数字 (First, Second, Third)

备注

此处不包含用于其他语言的其他选项。各种亚洲语言都有此列表中未涵盖的编号系统。

您将 w:lvlText 元素作为模板来构造列表项。对于级别 0,本例使用"%1.",它指示无论确定的是什么 w:numFmt 文本,最小缩进项都会替换格式字符串中的 %1。对于级别 1,本例使用"%2.",它指示无论确定的是什么文本,第一个缩进都会替换 %2。请注意,对于 w:lvl 元素,您使用从零开始的索引指定缩进级别,而在 w:lvlText 模板中,您使用从一开始的索引指定替换标记。这很合理。w:lvl 元素仅供开发人员使用,从零开始的索引对开发人员而言较为容易,而模板由用户使用和指定,因此从一开始的索引较有意义。这两个元素非常强大,使您能够创建几乎满足任何需要的分层列表格式。下文中提供了有关这两个元素的更多示例。

重要说明重要说明

对于点符列表,即使 w:lvltext 元素包含替换标记(如 %1 和 %2),替换标记也不会被级别编号替换。这不影响我们的代码,因为 w:lvlText 元素不含替换标记。

w:lvlJc 元素控制列表项是右对齐还是左对齐以及其他选项。下面显示使用文本的编号项目的左对齐与右对齐间的区别。虽然在本例中很容易看到区别,但如果您的点符列表或编号列表使用了数字,则会很难发现区别。

图 6. 对齐的列表项

列表项两端对齐

最后,有一些适用于列表项的段落属性,例如指定缩进和悬挂缩进。

w:lvl 元素也可以包含适用于列表项的运行属性。如果将列表项的字体改为 Courier,则它看上去如下所示。

图 7. 使用 courier 字体格式的列表项

设置了字体的列表项

下面是包含用于定义列表项字体的运行属性的 w:lvl 元素示例。

<w:lvl w:ilvl="0">
  <w:start w:val="1"/>
  <w:numFmt w:val="ordinalText"/>
  <w:lvlText w:val="%1)"/>
  <w:lvlJc w:val="left"/>
  <w:pPr>
    <w:ind w:left="720"
           w:hanging="360"/>
  </w:pPr>
  <w:rPr>
    <w:rFonts w:ascii="Courier New"
              w:hAnsi="Courier New"
              w:hint="default"/>
  </w:rPr>
</w:lvl>

像往常一样,主文档部件中的段落还包含对样式的引用。

<w:p>
  <w:pPr>
    <w:pStyle w:val="ListParagraph"/>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="1"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>One</w:t>
  </w:r>
</w:p>

我们可以在样式部件中找到该样式,它指定段落文本的格式。

<w:style w:type="paragraph"
         w:styleId="ListParagraph">
  <w:name w:val="List Paragraph"/>
  <w:basedOn w:val="Normal"/>
  <w:pPr>
    <w:ind w:left="720"/>
    <w:contextualSpacing/>
  </w:pPr>
</w:style>

这是应用了样式的段落的标记的典型模式。

简单点符列表标记

本节介绍创建简单点符列表时生成的标记,如下图所示。

图 8. 创建简单符号项目列表

点符列表

简单符号项目列表的标记间接寻址模式与简单编号列表的模式相同。

对于简单点符列表,主文档部件 (document.xml) 包含与简单编号列表完全相同的段落。

<w:p>
  <w:pPr>
    <w:pStyle w:val="ListParagraph"/>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="1"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>One</w:t>
  </w:r>
</w:p>

下面是编号部件的示例。

<w:abstractNum w:abstractNumId="0">
  <w:lvl w:ilvl="0">
    <w:start w:val="1"/>
    <w:numFmt w:val="bullet"/>
    <w:lvlText w:val="o"/>
    <w:lvlJc w:val="left"/>
    <w:pPr>
      <w:ind w:left="720"
             w:hanging="360"/>
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Symbol"
                w:hAnsi="Symbol"
                w:hint="default"/>
    </w:rPr>
  </w:lvl>
  <!-- several w:lvl elements elided -->
  <w:num w:numId="1">
    <w:abstractNumId w:val="0"/>
  </w:num>
</w:numbering>

此处的 w:lvlText 元素的 w:val 属性被另存为字符 0xB7,这是此级别的点符(来自 Symbol 字体)。此示例的要点在于您可以编写一种通用方法来组合列表项的文本,并且此方法同时适用于编号列表和点符列表。

w:start 元素不影响列表项,因为 w:lvlText 模板元素不包含替换标记(例如 %1 和 %2),但即使包含,我们也不会替换该标记。

多级列表标记

您可以看到此框架很容易实现多级列表。您可以将源文档更改为如下图所示。

图 9. 简单多级列表

带层次结构的列表

主文档部件中的段落如下所示。第二段的 w:ilvl 元素设置为"1"。

<w:p>
  <w:pPr>
    <w:pStyle w:val="ListParagraph"/>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="1"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>One</w:t>
  </w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pStyle w:val="ListParagraph"/>
    <w:numPr>
      <w:ilvl w:val="1"/>
      <w:numId w:val="1"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>Two</w:t>
  </w:r>
</w:p>

在本例中,没有修改编号和样式部件。

链接到样式的编号标记

有一种编号功能可为用户带来很大方便,但会使标记变得更加复杂。您可以将一种样式链接到一种编号类型和级别,然后用一个列表项表示该样式的所有段落。典型的例子是将标题 1 样式链接到第一个缩进级别,将标题 2 样式链接到第二个缩进级别。使用这种方法的文档看起来如下图所示。

图 10. 链接到样式的编号

带编号样式

链接到样式的编号的标记间接寻址模式如下所示。

图 11. 链接到样式的编号的间接寻址

设置样式的编号间接寻址

在本例中,主文档部件不包含与编号相关的任何标记。

<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading1"/>
  </w:pPr>
  <w:r>
    <w:t>Overview of Numbering</w:t>
  </w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading2"/>
  </w:pPr>
  <w:r>
    <w:t>Markup of a Simple Numbered List</w:t>
  </w:r>
</w:p>

标题 1 样式的样式部件中的标记包含对编号部件中 w:num 元素的引用。

<w:style w:type="paragraph"
         w:styleId="Heading1">
  <w:name w:val="heading 1"/>
  <w:basedOn w:val="Normal"/>
  <w:pPr>
    <w:numPr>
      <w:numId w:val="1"/>
    </w:numPr>
    <w:spacing w:before="480"
               w:after="0"/>
    <w:outlineLvl w:val="0"/>
  </w:pPr>
  <w:rPr>
    <w:rFonts w:asciiTheme="majorHAnsi"
              w:eastAsiaTheme="majorEastAsia"
              w:hAnsiTheme="majorHAnsi"
              w:cstheme="majorBidi"/>
    <w:b/>
    <w:bCs/>
    <w:color w:val="365F91"
             w:themeColor="accent1"
             w:themeShade="BF"/>
    <w:sz w:val="28"/>
    <w:szCs w:val="28"/>
  </w:rPr>
</w:style>

编号部件类似如下:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<w:numbering xmlns:w="https://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:abstractNum w:abstractNumId="0">
    <w:lvl w:ilvl="0">
      <w:start w:val="1"/>
      <w:numFmt w:val="decimal"/>
      <w:pStyle w:val="Heading1"/>
      <w:lvlText w:val="%1"/>
      <w:lvlJc w:val="left"/>
      <w:pPr>
        <w:ind w:left="432"
               w:hanging="432"/>
      </w:pPr>
    </w:lvl>
    <w:lvl w:ilvl="1">
      <w:start w:val="1"/>
      <w:numFmt w:val="decimal"/>
      <w:pStyle w:val="Heading2"/>
      <w:lvlText w:val="%1.%2"/>
      <w:lvlJc w:val="left"/>
      <w:pPr>
        <w:ind w:left="576"
               w:hanging="576"/>
      </w:pPr>
    </w:lvl>
    <!-- Remaining w:lvl elements elided -->
  </w:abstractNum>
  <w:num w:numId="1">
    <w:abstractNumId w:val="0"/>
  </w:num>
</w:numbering>

w:pStyle 元素链接回样式部件中的样式。通过查找与段落样式匹配的 w:pStyle 元素,可确定缩进级别。父 w:lvl 复杂元素定义缩进级别。与往常一样,您组合来自 w:lvl 元素的其他子元素的列表项文本。

用新的编号格式替代多级列表中的编号格式

通过使用新的编号格式,您可以替代多级列表中任何级别的编号格式。这会影响标记。要创建此标记,请先创建一个多级列表:

图 12. 创建多级列表

分层列表样式

然后选择一个段落,并定义一种新的编号格式:

图 13. 替代编号格式

定义新数字格式

在"定义新编号格式"对话框中,更改某些方面。本例中我们更改了标题 2,使列表项是后跟一个括号的基数:"One)"

图 14. "定义新编号格式"对话框

序号格式

主文档部件的标记现在看起来如下所示:

<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading1"/>
  </w:pPr>
  <w:r>
    <w:t>Paragraph One</w:t>
  </w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading2"/>
    <w:numPr>
      <w:ilvl w:val="1"/>
      <w:numId w:val="2"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>Paragraph Two</w:t>
  </w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading3"/>
  </w:pPr>
  <w:r>
    <w:t>Paragraph Three</w:t>
  </w:r>
</w:p>

编号部件中的标记现在有两个 w:num 元素,每个元素指向它们各自的抽象编号格式:

<w:num w:numId="1">
  <w:abstractNumId w:val="1"/>
</w:num>
<w:num w:numId="2">
  <w:abstractNumId w:val="0"/>
</w:num>

然后可以像往常那样处理抽象编号标记。此处的要点是当您使用样式设置编号格式时,标记将遵循本节中详述的间接寻址。如果该样式的段落包含 w:numPr 元素,这将替代从抽象编号格式到样式的链接。

替代多级列表中的编号格式,并创建多级列表格式

用户可以替代多级列表中任一级别的编号格式,创建多级列表格式,这会影响标记。要创建此标记,请先创建一个多级列表。

图 15. 创建多级列表

当前列表

然后选择一个段落,并定义新的多级列表。

图 16. 定义新的多级列表

定义新的多级列表对话框

在"定义新多级列表" 对话框中,更改列表级别的某些方面。我的示例更改了格式,使第二个缩进级别的列表项将大写 Alpha 用于项目标记。

图 17. "定义新多级列表"对话框

定义新的多级列表对话框 2

主文档部件的标记包含w:numPr 元素,该元素替代从抽象编号格式到样式的链接,这与创建编号格式时完全一样。

<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading1"/>
  </w:pPr>
  <w:r>
    <w:t>Paragraph One</w:t>
  </w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading2"/>
    <w:numPr>
      <w:ilvl w:val="1"/>
      <w:numId w:val="3"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>Paragraph Two</w:t>
  </w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading3"/>
  </w:pPr>
  <w:r>
    <w:t>Paragraph Three</w:t>
  </w:r>
</w:p>

段落属性中的 w:numPr 元素替代抽象编号格式和标题 2 样式之间的链接。编号部件现在包含一个新的w:num 元素,用来定义 w:lvlOverride 元素。

<w:num w:numId="1">
  <w:abstractNumId w:val="0"/>
</w:num>
<w:num w:numId="2">
  <w:abstractNumId w:val="1"/>
</w:num>
<w:num w:numId="3">
  <w:abstractNumId w:val="0"/>
  <w:lvlOverride w:ilvl="0">
    <w:lvl w:ilvl="0">
      <w:start w:val="1"/>
      <w:numFmt w:val="decimal"/>
      <w:pStyle w:val="Heading1"/>
      <w:lvlText w:val="%1"/>
      <w:lvlJc w:val="left"/>
      <w:pPr>
        <w:ind w:left="432"
               w:hanging="432"/>
      </w:pPr>
      <w:rPr>
        <w:rFonts w:hint="default"/>
      </w:rPr>
    </w:lvl>
  </w:lvlOverride>
  <w:lvlOverride w:ilvl="1">
    <w:lvl w:ilvl="1">
      <w:start w:val="1"/>
      <w:numFmt w:val="upperLetter"/>
      <w:pStyle w:val="Heading2"/>
      <w:lvlText w:val="%1.%2"/>
      <w:lvlJc w:val="left"/>
      <w:pPr>
        <w:ind w:left="576"
               w:hanging="576"/>
      </w:pPr>
      <w:rPr>
        <w:rFonts w:hint="default"/>
      </w:rPr>
    </w:lvl>
  </w:lvlOverride>
  . . .

两个 w:num 元素现在引用同一抽象编号格式。但是,第二个元素现在替代列表项格式。您可以看到级别 1 的级别替代现在指定 w:numFmt 元素的值为"upperLetter"。

处理 w:startOverride 元素

w:lvlOverride 元素可以包含一个子 w:startOverride 元素。

  <w:num w:numId="2">
    <w:abstractNumId w:val="2"/>
    <w:lvlOverride w:ilvl="0">
      <w:startOverride w:val="5"/>
    </w:lvlOverride>
    <w:lvlOverride w:ilvl="1">
      <w:startOverride w:val="1"/>
    </w:lvlOverride>
    . . .
  </w:num>

w:startOverride 元素可以使缩进级别的起始编号为指定的值。有时,当用户专门在用户界面中设置此值以强制继续从特定编号开始时,就需要这样做。这是标记构成可跳过编号列表中某个编号的文档的一种方式。

图 18. 跳过某个编号的编号列表

数字 4 被跳过

还有一种允许标记指定起始编号的方式。稍后会显示此标记。

定义列表样式

Word 中有一个选项允许您定义一个新的命名列表样式,然后在文档中的其他位置使用该样式。这是实现您自己的自定义编号格式的一种快速、简单的办法。为此,请选择要编号的文本,然后从多级列表选择"定义新列表样式"。

图 19. 定义新的列表样式

定义新列表样式

这将打开"定义新列表样式"对话框。

图 20. "定义新列表样式"对话框

定义新列表样式 2

完成此对话框后,选定段落将具有您指定的编号格式。然后,您也可以在文档中的其他位置应用这一样式。此功能影响标记。下面是您使用此模式时的间接寻址。

图 21. 列表样式的间接寻址

列表样式间接寻址

文档部件看上去与您应用其他形式的编号时一样。

<w:p>
  <w:pPr>
    <w:pStyle w:val="ListParagraph"/>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="2"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>1</w:t>
  </w:r>
</w:p>

我们可以在编号部件中找到引用的 w:num 元素。

<w:num w:numId="2">
  <w:abstractNumId w:val="0"/>
</w:num>

但如果我们看一下抽象编号元素,就会发现它看起来非常不同。它不包含子 w:lvl 元素,并使用 w:numStyleLink 元素来引用以前定义的样式。

<w:abstractNum w:abstractNumId="0">
  <w:nsid w:val="03916EF0"/>
  <w:multiLevelType w:val="multilevel"/>
  <w:tmpl w:val="0409001D"/>
  <w:numStyleLink w:val="EricsListStyle"/>
</w:abstractNum>

在样式部件中,您可以找到新定义的样式,该样式随后反过来引用编号部件中的 w:num 元素。

<w:style w:type="numbering"
         w:customStyle="1"
         w:styleId="EricsListStyle">
  <w:name w:val="EricsListStyle"/>
  <w:uiPriority w:val="99"/>
  <w:rsid w:val="00B1427D"/>
  <w:pPr>
    <w:numPr>
      <w:numId w:val="1"/>
    </w:numPr>
  </w:pPr>
</w:style>

编号部件中的 w:num 元素看起来如下所示。

<w:num w:numId="1">
  <w:abstractNumId w:val="1"/>
</w:num>

它引用 w:abstractNum 元素,后者与往常一样包含级别格式。

<w:abstractNum w:abstractNumId="1">
  <w:nsid w:val="2D235466"/>
  <w:multiLevelType w:val="multilevel"/>
  <w:tmpl w:val="0409001D"/>
  <w:styleLink w:val="EricsListStyle"/>
  <w:lvl w:ilvl="0">
    <w:start w:val="1"/>
    <w:numFmt w:val="decimal"/>
    <w:lvlText w:val="%1)"/>
    <w:lvlJc w:val="left"/>
    <w:pPr>
      <w:ind w:left="360"
             w:hanging="360"/>
    </w:pPr>
  </w:lvl>
  <w:lvl w:ilvl="1">
    <w:start w:val="1"/>
    <w:numFmt w:val="lowerLetter"/>
    <w:lvlText w:val="%2)"/>
    <w:lvlJc w:val="left"/>
    <w:pPr>
      <w:ind w:left="720"
             w:hanging="360"/>
    </w:pPr>
  </w:lvl>
  . . .

列表项后缀的备选项

列表后缀是列表项与段落之间的空白内容。只有两个可能的值:制表符和空格。我们可以改变列表定义以使用空格而非制表符作为列表项后缀。

图 22. 使用空格而非制表符为后缀的列表

一二三

标记使用 w:suff 元素指定后缀。

<w:abstractNum w:abstractNumId="0">
  <w:nsid w:val="21E167DA"/>
  <w:multiLevelType w:val="multilevel"/>
  <w:tmpl w:val="5BE82C98"/>
  <w:lvl w:ilvl="0">
    <w:start w:val="1"/>
    <w:numFmt w:val="decimal"/>
    <w:pStyle w:val="Heading1"/>
    <w:suff w:val="space"/>
    <w:lvlText w:val="%1"/>
    <w:lvlJc w:val="left"/>
    <w:pPr>
      <w:ind w:left="432"
             w:hanging="432"/>
    </w:pPr>
    <w:rPr>
      <w:rFonts w:hint="default"/>
    </w:rPr>
  </w:lvl>

处理 w:lvlRestart 元素

w:lvlRestart 元素允许标记控制某个特定级别何时重新开始计数。在以下示例中,当级别一中存在干预项目时,级别四列表项将开始重新计数:

图 23. 控制级别重新开始

重新开始重新编号

上例中 w:lvl 元素(其中 w:ilvl 属性等于"3")的标记看起来如下所示。

  <w:abstractNum w:abstractNumId="0">
    <w:nsid w:val="065A6A4E"/>
    <w:multiLevelType w:val="multilevel"/>
    <w:tmpl w:val="06A2CF44"/>
    <!-- several w:lvl elements elided -->
    <w:lvl w:ilvl="3">
      <w:start w:val="1"/>
      <w:numFmt w:val="decimal"/>
      <w:lvlRestart w:val="1"/>
      <w:lvlText w:val="%1.%2.%3.%4."/>
      <w:lvlJc w:val="left"/>
      <w:pPr>
        <w:ind w:left="1728"
               w:hanging="648"/>
      </w:pPr>
      <w:rPr>
        <w:rFonts w:hint="default"/>
      </w:rPr>
    </w:lvl>

处理 w:isLgl 元素

w:isLgl 元素更改列表项的文本表示形式以便它将数字用于所有级别,而非将指定编号格式用于该级别,但这种情况仅出现在为给定缩进级别设置文本格式时。考虑以下文档,其中第三个缩进级别处的项目使用合法编号。

图 24. 级别三使用合法编号的列表

合法编号

如果此列表没有对第三个缩进级别使用合法编号,它会显示为如下这样。

图 25. 未使用合法编号的列表

非法编号

w:isLgl 元素的标记如下所示。

<w:abstractNum w:abstractNumId="0">
  . . .
  <w:lvl w:ilvl="2">
    <w:start w:val="1"/>
    <w:numFmt w:val="decimal"/>
    <w:pStyle w:val="Heading3"/>
    <w:isLgl/>
    <w:lvlText w:val="%1.%2.%3)"/>
    <w:lvlJc w:val="left"/>
    <w:pPr>
      <w:ind w:left="720"
             w:hanging="720"/>
    </w:pPr>
    <w:rPr>
      <w:rFonts w:hint="default"/>
    </w:rPr>
  </w:lvl>

组合列表项文本的算法

若要组合列表项文本,您必须确定:

  1. 段落的 w:lvl 格式。

  2. 段落的缩进级别。

  3. 段落的每个父缩进级别的编号。例如,如果段落位于第四个缩进级别,则必须确定与该段落关联的第一、第二、第三和第四级的级别号。

拥有这三项后,组合列表项文本只不过是一个简单的设置文本格式的操作。

段落可能包含具有 w:ilvl 和 w:numId 元素的编号属性。

<w:p>
  <w:pPr>
    <w:pStyle w:val="ListParagraph"/>
    <w:numPr>
      <w:ilvl w:val="0"/>
      <w:numId w:val="1"/>
    </w:numPr>
  </w:pPr>
  <w:r>
    <w:t>Paragraph one.</w:t>
  </w:r>
</w:p>

在此示例中,使用为缩进级别指定的 w:ilvl。转到编号部件,查找 w:num 元素。如果存在包含 w:lvl 元素的 w:lvlOverride 元素,则 w:lvl 元素适用。如果没有 w:lvlOverride 元素,或者 w:lvlOverride 元素不包含缩进级别的w:lvl 元素,则查找关联 w:abstractNum 元素,并使用在 w:abstractNum 中指定的 w:lvl 格式。如果 w:num 元素包含 w:lvlOverride 元素,使用在替代中为缩进级别指定的 w:lvl 元素。

如果段落不包含 w:numPr 复杂元素,并且段落样式包含 w:numPr 元素,则存在一个引用该样式的抽象编号元素。使用引用该样式的 w:lvl。这同样会提供缩进级别。

确定 w:lvl 格式元素和缩进级别后,您可以确定每个级别的列表编号。必须统计同一级别中当前段落之前的段落,同时注意 w:lvlRestart 元素和 w:start 元素。这里最适合函数编程。您可以构建一个无状态表达式来计算每个缩进级别的项目数。这可能不是完成此任务的最有效方式。它可能比另一种方法使用更多的 CPU 处理,但却很容易调试,并且对大多数应用场景而言,它可能足够快。我在我的速度最慢计算机上做过非正式测试,它仍然能够几乎在瞬间完成。

具有适当的 w:lvl 元素和每个缩进级别的项目编号列表后,创建列表项文本只不过是一个简单的文本组合过程而已。

结论

Open XML WordprocessingML 中的编号很复杂,这也是理所当然的。在准确提取文档文本时,理解编号非常重要。此外,生成使用编号标记的文档是文档组合解决方案中的一种有效方法。

其他资源

要开始使用 Open XML,请参阅 MSDN 上的 Open XML Developer Center(该链接可能指向英文页面)。那儿提供有大量内容,包括文章、操作方法视频和指向众多博客的链接。特别地,下面的链接提供重要信息,有助您开始使用 Open XML SDK 2.0: