使用 Open XML SDK 2.0 检索 Word 2010 文档中目录

Office 可视操作方法

**摘要:**使用 Open XML SDK 2.0 中的强类型类可检索包含 Word 文档中的目录的 XML 块,而无需将文档加载到 Microsoft Word 中。

上次修改时间: 2015年3月9日

适用范围: Excel 2010 | Office 2007 | Office 2010 | Open XML | PowerPoint 2010 | VBA | Word 2010

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

**供稿人:**Ken Getz,MCW Technologies, LLC(该链接可能指向英文页面)

概述

利用 Open XML 文件格式,可以检索 Word 文档中的内容块。Open XML SDK 2.0 添加了强类型类,可简化对 Open XML 文件格式的访问:SDK 将简化检索任务(具体而言,检索包含目录的 XML 块)。此直观操作方法附带的代码示例将介绍如何使用 SDK 来实现此目标。

编码

此直观操作方法附带的示例包含检索 XML 代码块所需的代码,该代码块包含 Word 2007 或 Word 2010 文档的目录。Word 提供了插入目录的多种方法。仅其中的一部分方法可生成允许代码正常运行的内部 XML 结构,如此直观操作方法中所示。有关详细信息,请参阅"读取"一节。以下各节演示了代码。请注意,文档的目录仅在该文档的作者使用 Word 用户界面已显式创建它的情况下才存在,并且目录包含一个描述文档内的参考的 XML 块。当您使用示例代码检索目录时,该过程将返回一个名为 TOC 的 XML 元素,其中包含原始文档中的 XML 信息块。您(及您的应用程序)必须解释检索目录所获得的结果。

设置引用

若要使用 Open XML SDK 2.0 中的代码,您必须向您的项目添加多个引用。虽然示例项目已包含这些引用,但您必须在您的代码中显式引用以下程序集:

  • WindowsBase - 可以根据您创建的项目的类型为您设置此引用。

  • DocumentFormat.OpenXml - 由 Open XML SDK 2.0 安装。

此外,您应在代码文件的顶部添加 using 和 Imports 语句,如下面的示例中所示。

Imports DocumentFormat.OpenXml
Imports DocumentFormat.OpenXml.Packaging
Imports DocumentFormat.OpenXml.Wordprocessing
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;

检查过程

WDRetrieveTOC 过程将接受一个指示要从中检索目录的文档的名称的参数(字符串)。此过程将返回一个包含名为 TOC 的元素的 XElement 实例,该元素将目录作为 XML 元素(或 空 引用,如果目录不存在)包含。

Public Function WDRetrieveTOC(ByVal fileName As String) As XElement
public static XElement WDRetrieveTOC(string fileName)

此过程将检查您指定的文档,并查找特定目录元素。如果该元素存在,则此过程返回该元素,且包装在一个名为 TOC 的元素中。若要调用此过程,请传递参数值,如示例代码中所示。在您运行示例代码之前,请确认您提供了一个名为 C:\temp\TOC.docx 的文档,该文档(用于演示)包含一个目录。

Dim result = WDRetrieveTOC("C:\Temp\TOC.docx")
Console.WriteLine(result.Value)
var result = WDRetrieveTOC(@"C:\temp\toc.docx");
Console.WriteLine(result.Value.ToString());

访问文档

首先,创建一个名为 TOC 的变量,此过程在退出之前将返回该变量。

Dim TOC As XElement = Nothing
' Code removed here…
Return TOC
XElement TOC = null;
// Code removed here…
return TOC;

然后,代码将使用 WordprocessingDocument.Open 方法打开文档,并指示应打开此文档以供只读访问(最后的 false 参数)。在打开文档的情况下,代码将使用 MainDocumentPart 属性以导航到主文档,然后使用部分的 Document 属性以检索对主文档部分的内容的引用。代码将在一个名为 doc 的变量中存储此引用。

Using document = WordprocessingDocument.Open(fileName, False)
  Dim docPart = document.MainDocumentPart
  Dim doc = docPart.Document
  ' Code removed here…
End Using
using (var document = WordprocessingDocument.Open(fileName, false))
{
  var docPart = document.MainDocumentPart;
  var doc = docPart.Document;
  // Code removed here…
}

查找目录

通过在文档的后代中进行搜索来继续执行示例过程,并查找具有"Table of Contents"值的类型为 DocPartGallery 的 XML 元素。代码将返回对第一个匹配元素(或 空 引用,如果不存在任何元素)的引用。代码将使用该元素的 Val 属性的 HasValue 属性以确保存在此值,并确保在代码尝试检索此值之前存在一个值。

Dim block As OpenXmlElement = _
  doc.Descendants(Of DocPartGallery)().
  Where(Function(b) b.Val.HasValue AndAlso
          (b.Val.Value = "Table of Contents")).FirstOrDefault()
OpenXmlElement block = doc.Descendants<DocPartGallery>().
  Where(b => b.Val.HasValue && 
    (b.Val.Value == "Table of Contents")).FirstOrDefault();

查找父级并创建返回值

当代码找到目录标记元素时,它必须向上遍历元素的层次结构,直至找到包含完整目录信息的父 SdtBlock 元素。当 block 变量不是 空 引用且 block 变量的类别不是 SdtBlock 时,代码将循环,并设置 block 变量,使其引用其父节点。当循环最终结束时,代码会将 TOC 变量设置为包含 block 变量的 OuterXml 属性(在循环访问父元素后,代码不会验证 block 是否为 空 引用 - 如果 block 为 空 ,则将引发异常,以指示该文档的格式不正确)。

If block IsNot Nothing Then
  ' Back up to the enclosing SdtBlock and return that XML.
  Do While (block IsNot Nothing) AndAlso (Not TypeOf block Is SdtBlock)
    block = block.Parent
  Loop
  TOC = New XElement("TOC", block.OuterXml)
End If
if (block != null)
{
  // Back up to the enclosing SdtBlock and return that XML.
  while ((block != null) && (!(block is SdtBlock)))
  {
    block = block.Parent;
  }
  TOC = new XElement("TOC", block.OuterXml);
}

示例过程

下面的代码示例包含完整的示例过程。

Public Function WDRetrieveTOC(ByVal fileName As String) As XElement
    Dim TOC As XElement = Nothing

    Using document = WordprocessingDocument.Open(fileName, False)
      Dim docPart = document.MainDocumentPart
      Dim doc = docPart.Document

      Dim block As OpenXmlElement = _
        doc.Descendants(Of DocPartGallery)().
        Where(Function(b) b.Val.HasValue AndAlso
                (b.Val.Value = "Table of Contents")).FirstOrDefault()
      If block IsNot Nothing Then
        ' Back up to the enclosing SdtBlock and return that XML.
        Do While (block IsNot Nothing) AndAlso 
         (Not TypeOf block Is SdtBlock)
          block = block.Parent
        Loop
        TOC = New XElement("TOC", block.OuterXml)
      End If
    End Using
    Return TOC
  End Function
public static XElement WDRetrieveTOC(string fileName)
{
  XElement TOC = null;

  using (var document = WordprocessingDocument.Open(fileName, false))
  {
    var docPart = document.MainDocumentPart;
    var doc = docPart.Document;

    OpenXmlElement block = doc.Descendants<DocPartGallery>().
      Where(b => b.Val.HasValue && 
        (b.Val.Value == "Table of Contents")).FirstOrDefault();

    if (block != null)
    {
      // Back up to the enclosing SdtBlock and return that XML.
      while ((block != null) && (!(block is SdtBlock)))
      {
        block = block.Parent;
      }
      TOC = new XElement("TOC", block.OuterXml);
    }
  }
  return TOC;
}
读取

此直观操作方法附带的示例描述了检索 Word 文档中的目录的代码。若要使用该示例,必须安装 Open XML SDK 2.0(可通过"浏览"一节中列出的链接获得)。该示例还将使用作为 Open XML SDK 2.0 代码示例集的一部分包含的修改后的代码。"浏览"一节还包括指向完整代码示例集的链接,但您无需下载并安装代码示例即可使用该示例。

请注意,Word 提供了至少四种用于将目录插入文档中的不同方法。其中的两种方法将生成内部 XML 代码,该代码将与此直观操作方法中所示的代码一起使用。具体而言,以下两种方法提供了用 SdtBlock 元素嵌套的目录:

  • 使用内置设计 - 在"引用"选项卡上的"目录"组中,单击"目录",并从选项库(当前,有三个选项)中选择一个内置设计。

  • 使用来自 Office.com 条目的"更多目录"- 在"引用"选项卡上的"目录"组中,单击"目录",然后单击底部附近的来自 Office.com 的"更多目录"。

以下两种方法(也可用于在文档中生成有效目录)不会在 SdtBlock 元素内嵌套目录,这将导致此直观操作方法中显示的代码无法正常工作:

  • 使用"插入目录"条目 - 在"引用"选项卡上的"目录"组中,单击"目录",然后单击底部附近的"插入目录"。

  • 使用"插入字段"选项 - 在"插入"选项卡上的"文本组"中,单击"文档部件",然后单击"字段"。在"字段名称"下,依次单击"TOC"、"目录"(可选)和"确定"。

这两个选项可创建独立的目录元素,并要求更复杂的代码以从文档中提取目录。如果您从 Word 2007 之前的 Word 版本中导入文档,则代码也将无法正常工作,因为在这些版本中,Word 从不围绕目录元素使用 SdtBlock。

若要了解示例代码,则使用 Open XML SDK 2.0 Productivity Tool for Microsoft Office(作为 Open XML SDK 2.0 的一部分包含)检查文档的内容会很有用。图 1 演示了一个在工具中打开的包含目录的示例文档。示例代码将检索对 Document 部分的引用,并在该部分中,使用 value:Table of Contents 查找 DocumentPartGallery 元素(称作 w:docPartGallery)。

图 1. 打开示例文档并查找元素

打开示例文档并找到相关元素

示例应用程序仅演示了由 Open XML SDK 2.0 提供的一些可用来修改文档结构的可用属性和方法。有关详细信息,请参阅 Open XML SDK 2.0 Productivity Tool 附带的文档。单击应用程序窗口左下角的"Open XML SDK 文档"选项卡,并搜索要研究的类。尽管该文档当前不包含代码示例,但借助此处所示的示例和文档,您应能成功修改示例应用程序。

观看

观看视频

观看视频(该链接可能指向英文页面) | 时长:00:09:53

单击以获取代码

获取代码(该链接可能指向英文页面)

浏览

关于作者
Ken Getz 是 MCW Technologies 的高级顾问。他是 ASP.NET Developers Jumpstart(《ASP.NET 开发人员入门》,Addison-Wesley,2002)、Access Developer's Handbook(《Access 开发人员手册》,Sybex,2001)和 VBA Developer's Handbook, 2nd Edition(《VBA 开发人员手册第 2 版》,Sybex,2001)的合著者。