OpenXML (Word 2007) 初学者指南
OpenXML 格式简介。
引言
自 Microsoft 在 Office 2007 中推出 OpenXML 以来,许多人都开始考虑是否能利用它。然而,如果您在新闻组/社区/论坛上搜索,会发现学习和实现它要复杂和困难得多。
我认为它并非难,只是过程冗长且有些复杂。
ODF vs. OpenXML:这是另一个争论点。ODF(OpenDocument Format)比 MS OpenXML 简单。两者都遵循相同的 XML + Zip 格式。然而,与 MS 产品相比,开源技术在这方面的帮助/教程/支持方面有所欠缺。
本文:我将在此解释 OpenXML 编程的基础知识,以帮助初学者。我处理过 Word 2007,因此我将仅涵盖 Word 2007 的部分。但是,OpenXML 在 Office 组件之间的实现方式非常相似。
这并非我的新发明,而是我将互联网上分散的基本事实汇集在一起。
基础
让我们从基础开始。扩展名为 DOCX 的 Word 文件实际上是一个包含一些文件的压缩存档(Zip)。这些文件只不过是 XML 文件和一些文件夹/子文件夹。这些文件通过“*关系*”相互关联。
下图显示了 DOCX 文件内部的文件
要查看这些文件,只需使用 WinZip(或您拥有的任何其他软件)打开 DOCX 文件即可。除少数例外(如图像、ActiveX),所有内容都已转换为 XML。您需要记住以下关键字:“*Package*”、“*Parts*”、“*Relations*”。
Package(包):Package 就是您的 DOCX 文件。这个 zip 文件称为 Package。
Parts(部分):Parts 就是 Package 中的文件。例如,您在(打开 Word 后)键入的区域是主文档部分。如果您插入图像,它将成为另一个部分。所有内容都以 Parts 的形式进行管理(编号 [项目符号]、图像、样式、设置等)。如果您想插入/删除/检索图像,那么您将需要操作 ImageParts(Parts 的一个子类)等等。
Relations(关系):Parts 之间通过关系链接。主要关系保存在 Package 内 _rels 文件夹中的 *.rels 文件中。当然,您可以在此文件中找到 XML 标签。在 word/_rels 文件夹中还有其他关系文件。这些是子关系。例如,如果您为项目符号(图片项目符号)包含图像,您可以在此文件夹中找到 numbering.xml.rels 文件。还有许多其他关系文件,很难全部列出。
Relations IDs(关系 ID):每个关系都有一个唯一的 ID。这在引用部分和关系文件中都有引用。通过此 ID,Office 会搜索适当的被引用部分并按相应方式显示它们。例如,在文档中添加新图像,然后保存。用 WinZip 打开它。打开 document.xml,查找 w:drawing
标签,然后在其中查找 a:blip r:embed
标签。此标签的值将类似于 rId2.
。然后,打开 document.xml.rels 文件并搜索 rId2
;您将在 Package 中找到图像的路径!
动手操作
要以编程方式处理 DOCX 并简化编程,您可以下载 此 SDK [Microsoft SDK for OpenXML Formats] [SDK 2.0 在此],由 Microsoft 提供。最终版本尚未发布。下载它 -> 在您的项目中添加引用 -> 导入它。
代码
打开文档
Dim doc As WordprocessingDocument = _
WordprocessingDocument.Open("C:\Test\abc.docx", True)
Dim mainDoc As MainDocumentPart = doc.MainDocumentPart
MainDoc
是主文档(document.xml),包含您在文档中键入的所有文本行。
加载到 XMLDocument 中
您可能希望将 document.xml 的 XML 加载到 XMLDocument
类对象中。试试这个:
Dim streamReader As System.IO.StreamReader = New IO.StreamReader(mainDoc.GetStream)
Dim str As String = streamReader.ReadToEnd
Dim xmlDoc As New System.Xml.XmlDocument
xmlDoc.LoadXml(str)
请记住,要在 XML 中进行导航,您需要 XmlNamespaceManager
并将所需的命名空间添加到其中。您可以在 document.xml 文件中添加所需的命名空间。如果您想添加段落,请在 xmlDoc
中添加子节点,然后保存 xmlDoc
(xmlDoc.Save(mainDoc.GetStream())
)。
添加新部分
要添加新部分,您可以使用 WordprocessingDocument
和 MainDocumentPart
类的 AddPart
和 AddNewPart
方法。这些是泛型方法,您需要指定要添加的部分。该方法会返回您添加的部分,然后您可以对其进行操作。
示例 1
要在主文档中添加新的编号部分,请尝试以下操作:
Dim numPart As NumberingDefinitionsPartnumPart = _
mainDoc.AddNewPart(Of NumberingDefinitionsPart)()
使用 GetStream
方法将 numPart
的 XML 加载到 XmlDocument
中,进行操作,然后保存。
示例 2
要在主文档中添加新的图像部分,请尝试以下操作:
Dim doc As WordprocessingDocument = WordprocessingDocument.Open("C:\Test\abc.docx", True)
Dim mainDoc As MainDocumentPart = doc.MainDocumentPart
Dim iPartImage As ImagePart = mainDoc.AddImagePart(ImagePartType.Png)
Dim img As Image = Image.FromFile("C:\images\test.gif")
img.Save(iPartImage.GetStream(), Imaging.ImageFormat.Png)
doc.Close()
上面的代码将在 Package 中添加一个图像。请记住,除非您手动添加段落和 mainDoc
的 XML 中所需的节点,否则它不会显示在您的文档中。执行完上述代码后,使用 WinZip 打开 Package,并检查图像是否已添加到 _media_ 文件夹下。另外,检查 relation 文件 document.xml.rels 并搜索 media/image;您会发现已添加了一个新的 relation 标签,并为此图像创建了一个新的唯一 ID。
[本文 将帮助您添加新段落。]
您可以使用 Part
类的 Parts
属性遍历每个部分。尝试使用 for-each 循环并在调试模式下检查每个部分(在 for-each 循环内设置断点)。[检查 mainDoc.Parts p
属性]。
删除现有部分
您可以在 document.xml 中看到部分的 ID。一旦有了部分的 ID,就调用 mainDoc
的 GetPartById
方法。这将返回您想要删除的部分。然后,调用 DeletePart
方法。这将删除该部分并更新 relation 文件(document.xml.rels)。
保存文档
WordprocessingDocument.Close()
会自动保存并关闭文档。您无需显式保存。
结束语
您需要努力工作才能理解 OpenXML。调试和一些研发将帮助您更好地了解它。