替换字处理文档中的页眉

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

页眉引用元素的结构

在此示例中,您将从目标文件中删除页眉部件并创建另一个页眉部件。 您还将删除对现有页眉的引用并创建对新页眉的引用。 因此,熟悉标头和标头引用元素非常有用。 ISO/IEC 29500 规范中的以下信息介绍了标头引用元素。

headerReference(页眉引用)

该元素指定将与文档中的当前节关联的单个页眉。 将通过 id 属性引用该页眉,该属性指定与 WordprocessingML 包中相应页眉部件之间的显式关系。

如果此元素指定的关系类型不是 https://schemas.openxmlformats.org/officeDocument/2006/header、不存在或没有 TargetMode 属性值 为 Internal,则文档应被视为不一致。

在文档的每节中,最多可以存在三种不同类型的页眉:

  • 第一页页眉

  • 奇数页页眉

  • 偶数页页眉

通过 type 属性指定由当前 headerReference 指定的页眉类型。

如果给定节忽略了任意类型的页眉,则以下规则适用。

  • 如果没有为第一页指定 headerReference 但指定了 titlePg 元素,则从上一节继承第一页页眉;如果这是文档的第一节,则创建新的空白页眉。 如果未指定 titlePg 元素,则不显示第一页页眉,并在其位置使用奇数页页眉。

  • 如果没有为偶数页页眉指定 headerReference 但指定了 evenAndOddHeaders 元素,则从上一节继承偶数页页眉;如果这是文档的第一节,则创建新的空白页眉。 如果未指定 evenAndOddHeaders 元素,则不显示偶数页页眉,并在其位置使用奇数页页眉。

  • 如果没有为奇数页页眉指定 headerReference ,则从上一节继承偶数页页眉;如果这是文档的第一节,则创建新的空白页眉。

示例:考虑一个三页文档,其中定义了不同的第一个、奇数和偶数页标题,如下所示:

具有不同页眉的三页文档

该文档定义三种页眉,每种页眉与具有唯一关系 ID 的文档部件存在关系,如以下包装标记中所示:

    <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
      …
      <Relationship Id="rId2" Type="https://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml" />
      <Relationship Id="rId3" Type="https://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header2.xml" />
      <Relationship Id="rId5" Type="https://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header3.xml" />
      …
    </Relationships>

然后,在节的属性中使用以下 WordprocessingML 引用这些关系:

    <w:sectPr>  
      …  
      <w:headerReference r:id="rId3" w:type="first" />  
      <w:headerReference r:id="rId5" w:type="default" />  
      <w:headerReference r:id="rId2" w:type="even" />  
      …  
    </w:sectPr>  

产生的节会将关系 ID 为 rId3 的页眉部件用于第一页,将关系 ID 为 rId2 的页眉部件用于所有后续偶数页,将关系 ID 为 rId5 的页眉部件用于所有后续奇数页。 end 示例

© ISO/IEC 29500:2016

示例代码

下面的代码示例演示如何将一个字处理文档中的页眉替换为另一个字处理文档中的页眉。 若要调用 方法, AddHeaderFromTo可以使用以下代码段作为示例。

string fromFile = args[0];
string toFile = args[1];

AddHeaderFromTo(fromFile, toFile);

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

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Linq;


static void AddHeaderFromTo(string fromFile, string toFile)
{
    // Replace header in target document with header of source document.
    using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(toFile, true))
    using (WordprocessingDocument wdDocSource = WordprocessingDocument.Open(fromFile, true))
    {
        if (wdDocSource.MainDocumentPart is null || wdDocSource.MainDocumentPart.HeaderParts is null)
        {
            throw new ArgumentNullException("MainDocumentPart and/or HeaderParts is null.");
        }

        if (wdDoc.MainDocumentPart is null)
        {
            throw new ArgumentNullException("MainDocumentPart is null.");
        }

        MainDocumentPart mainPart = wdDoc.MainDocumentPart;

        // Delete the existing header part.
        mainPart.DeleteParts(mainPart.HeaderParts);

        // Create a new header part.
        DocumentFormat.OpenXml.Packaging.HeaderPart headerPart = mainPart.AddNewPart<HeaderPart>();

        // Get Id of the headerPart.
        string rId = mainPart.GetIdOfPart(headerPart);

        // Feed target headerPart with source headerPart.

        DocumentFormat.OpenXml.Packaging.HeaderPart? firstHeader = wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();

        wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();

        if (firstHeader is not null)
        {
            headerPart.FeedData(firstHeader.GetStream());
        }

        if (mainPart.Document.Body is null)
        {
            throw new ArgumentNullException("Body is null.");
        }

        // Get SectionProperties and Replace HeaderReference with new Id.
        IEnumerable<DocumentFormat.OpenXml.Wordprocessing.SectionProperties> sectPrs = mainPart.Document.Body.Elements<SectionProperties>();
        foreach (var sectPr in sectPrs)
        {
            // Delete existing references to headers.
            sectPr.RemoveAllChildren<HeaderReference>();

            // Create the new header reference node.
            sectPr.PrependChild<HeaderReference>(new HeaderReference() { Id = rId });
        }
    }
}