替换字处理文档中的主题部分

本主题演示如何使用 Open XML SDK for Office 中的类以编程方式替换字处理文档中的文档部件。

包和文档部件

Open XML 文档以包的形式存储,其格式由 ISO/IEC 29500-2(该链接可能指向英文页面) 定义。 包可以具有多个彼此之间存在关系的部件。 部件之间的关系控制文档的类别。 如果文档的包关系项包含与主文档部件的关系,可将文档定义为字处理文档。 如果文档的包关系项包含与演示文稿部件的关系,可将文档定义为演示文稿文档。 如果文档的包关系项包含与工作簿部件的关系,可将文档定义为电子表格文档。 在本操作方法主题中,您将使用字处理文档包。

获取 WordprocessingDocument 对象

在该示例代码中,首先如以下 using 语句所示通过实例化WordprocessingDocument 类打开字处理文件。 在同一语句中,使用 Open 方法打开字处理文件文档,并将布尔参数设置为 true 以允许编辑文档。

    using (WordprocessingDocument wordDoc = 
            WordprocessingDocument.Open(document, true))
    {
        // Insert other code here.
    }

using 语句提供典型 .Open, .Save, .Close 序列的建议备选序列。 它确保在遇到右大括号时会自动调用 Dispose 方法(Open XML SDK 用来清理资源的内部方法)。 using 语句后面的块为 using 语句中创建或指定的对象设定范围,在此示例中这个范围就是 wordDoc。 由于 Open XML SDK 中的 WordprocessingDocument 类会在实现其 System.IDisposable 的过程中自动保存和关闭对象,并且由于在您退出代码块时会自动调用 Dispose,因此只要您使用 using,就不必明确调用 SaveClose

如何在 Word 包中更改主题

如果要在 Word 文档中更改主题,请单击功能区"页面布局",然后单击"主题"。 "主题"下拉菜单将打开。 若要选择内置主题之一并将其应用于 Word 文档,请单击该主题图标。 也可以使用“浏览主题...”选项,在计算机中查找并应用主题文件。

主题元素的结构

主题元素由颜色、字体和格式架构组成。 在本操作方法主题中,您将学习如何以编程方式更改主题。 因此,熟悉主题元素会很有帮助。 ISO/IEC 29500(该链接可能指向英文页面) 规范中的以下信息在处理此元素时会很有用。

此元素定义与共享样式表(或主题)关联的根级别复杂类型。 此元素保留通过主题提供给文档的所有不同的格式选项并定义在文档中使用主题对象时文档的总体外观。

[示例:请考虑以下图像示例中应用于演示文稿的不同主题。 在此示例中,可以查看主题如何影响演示文稿中不同对象的字体、颜色、背景、填充和效果。 示例结束]

主题示例 在此示例中,我们了解主题如何影响演示文稿中不同对象的字体、颜色、背景、填充和效果。 示例结束]

© ISO/IEC29500: 2008.

下表列出 Theme 类可能的子类型。

PresentationML 元素 Open XML SDK 类 说明
custClrLst CustomColorList 自定义颜色列表
extLst ExtensionList 扩展名列表
extraClrSchemeLst ExtraColorSchemeList 额外配色方案列表
objectDefaults ObjectDefaults 对象默认值
themeElements ThemeElements 主题元素

下面的 XML 架构段定义主题元素的四个部件。 themeElements 元素是保留主题中定义的主要格式的部件。 其他部件提供 themeElements 中所包含信息的重载、默认值和附加内容。 定义主题 CT_OfficeStyleSheet 的复杂类型通过以下方式定义:

    <complexType name="CT_OfficeStyleSheet">
       <sequence>
           <element name="themeElements" type="CT_BaseStyles" minOccurs="1" maxOccurs="1"/>
           <element name="objectDefaults" type="CT_ObjectStyleDefaults" minOccurs="0" maxOccurs="1"/>
           <element name="extraClrSchemeLst" type="CT_ColorSchemeList" minOccurs="0" maxOccurs="1"/>
           <element name="custClrLst" type="CT_CustomColorList" minOccurs="0" maxOccurs="1"/>
           <element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
       </sequence>
       <attribute name="name" type="xsd:string" use="optional" default=""/>
    </complexType>

此复杂类型还保留一个 CT_OfficeArtExtensionList,它用于将来对此复杂类型进行扩展。

示例代码的工作方式

打开文件后,可以实例化 wordDoc 对象中的 MainDocumentPart,并删除旧主题部件。

    public static void ReplaceTheme(string document, string themeFile)
    {
        using (WordprocessingDocument wordDoc =
            WordprocessingDocument.Open(document, true))
        {
            MainDocumentPart mainPart = wordDoc.MainDocumentPart;

            // Delete the old document part.
            mainPart.DeletePart(mainPart.ThemePart);

然后,可以创建一个新 ThemePart 对象并将其添加到 MainDocumentPart 对象中。 然后,使用 StreamReaderStreamWriter 对象添加内容,将主题从 themeFile 复制到 ThemePart 对象。

    // Add a new document part and then add content.
    ThemePart themePart = mainPart.AddNewPart<ThemePart>();

    using (StreamReader streamReader = new StreamReader(themeFile))
    using (StreamWriter streamWriter =
        new StreamWriter(themePart.GetStream(FileMode.Create)))
    {
        streamWriter.Write(streamReader.ReadToEnd());
    }

示例代码

下面的代码示例演示如何将一个字处理文档中的主题文档部件替换为另一个包中的主题部件。 作为第二个参数传递的主题文件必须是采用 XML 格式的有效主题部件(如 Theme1.xml)。 您可以从已重命名为 .Zip 文件的现有文档或主题文件 (.THMX) 中提取此部件。 若要调用方法 ReplaceTheme,可以使用以下调用示例从文件"Theme1.xml"向文件"MyPkg7.docx"中复制主题。

    string document = @"C:\Users\Public\Documents\\MyPkg7.docx";
    string themeFile = @"C:\Users\Public\Documents\Theme1.xml";
    ReplaceTheme(document, themeFile);

运行程序后,打开 Word 文件并注意字体的更改。

以下是使用 C# 和 Visual Basic 编写的完整示例代码。

using DocumentFormat.OpenXml.Packaging;
using System;
using System.IO;

ReplaceTheme(args[0], args[1]);

// This method can be used to replace the theme part in a package.
static void ReplaceTheme(string document, string themeFile)
{
    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
    {
        if (wordDoc.MainDocumentPart is null || wordDoc.MainDocumentPart.Document.Body is null || wordDoc.MainDocumentPart.ThemePart is null)
        {
            throw new ArgumentNullException("MainDocumentPart and/or Body and/or ThemePart is null.");
        }

        MainDocumentPart mainPart = wordDoc.MainDocumentPart;

        // Delete the old document part.
        mainPart.DeletePart(mainPart.ThemePart);

        // Add a new document part and then add content.
        ThemePart themePart = mainPart.AddNewPart<ThemePart>();

        using (StreamReader streamReader = new StreamReader(themeFile))
        using (StreamWriter streamWriter = new StreamWriter(themePart.GetStream(FileMode.Create)))
        {
            streamWriter.Write(streamReader.ReadToEnd());
        }
    }
}