OpenXml:目录更新,出现错误!未定义书签

问题描述 投票:0回答:1

我正在使用OpenXml实用程序将内容动态添加到Word文档中,然后我想更新目录。

        var byteTempArray = File.ReadAllBytes("Sample.docx");
        var _memoryStream = new MemoryStream();
        _memoryStream.Write(byteTempArray, 0, byteTempArray.Length);
        var _wordprocessingDocument = WordprocessingDocument.Open(_memoryStream, true);
        var bodyDoc = _wordprocessingDocument.MainDocumentPart.Document.Body;
        SimpleField f = new SimpleField
        {
            Instruction = "sdtContent",
            Dirty = true
        };
        bodyDoc.AppendChild(f);
        _wordprocessingDocument.MainDocumentPart.Document.Save();
        _wordprocessingDocument.Close();
        File.WriteAllBytes(Guid.NewGuid()+".docx", _memoryStream.ToArray());

我已在Dirty设置为true的文档中附加了SimpleField。当我打开生成的文件时,它显示下面的确认消息以更新目录。单击是,将正确更新目录。

enter image description here

但是问题是错误!未定义书签。文本被附加在文档的底部。

任何想法如何通过适当的目录更新功能来删除此错误消息。

c# openxml-sdk tableofcontents
1个回答
0
投票

我对您要执行的操作的理解是,一旦用户使用Microsoft Word打开该文档,就会在文档中插入一个脏的w:fldSimple元素(SimpleField类),以使Word更新包括TOC在内的所有字段。但是,如果在更新字段后查看Microsoft Word生成的Open XML标记,您会发现w:fldSimple是罪魁祸首。

我创建了以下代码,以生成一个(几乎)仅有一个字段的简单Word文档:

[Fact]
public void CheckBookmarkNotDefined()
{
    using WordprocessingDocument wordDocument = WordprocessingDocument.Create(
        "SimpleField.docx", WordprocessingDocumentType.Document);

    MainDocumentPart part = wordDocument.AddMainDocumentPart();
    part.Document =
        new Document(
            new Body(
                new Paragraph(
                    new SimpleField
                    {
                        Instruction = "sdtContent",
                        Dirty = true
                    })));
}

以上代码在主文档部分中创建以下Open XML标记:

<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:body>
    <w:p>
      <w:fldSimple w:instr="sdtContent" w:dirty="true" />
    </w:p>
  </w:body>
</w:document>

请注意,w:fldSimple元素包含在w:p元素(Paragraph类)中,因为将其添加到w:body元素(Body类)会产生无效的Open XML标记。

[在Microsoft Word中打开该文档,更新字段并保存文档,使Word创建以下Open XML标记(我已经简化了一点):

<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:body>
    <w:p>
      <w:r>
        <w:fldChar w:fldCharType="begin"/>
      </w:r>
      <w:r>
        <w:instrText>sdtContent</w:instrText>
      </w:r>
      <w:r>
        <w:fldChar w:fldCharType="separate"/>
      </w:r>
      <w:r>
        <w:rPr>
          <w:b/>
          <w:bCs/>
        </w:rPr>
        <w:t>Error! Bookmark not defined.</w:t>
      </w:r>
      <w:r>
        <w:fldChar w:fldCharType="end"/>
      </w:r>
    </w:p>
    <w:sectPr>
      [Child elements removed for clarity]
    </w:sectPr>
  </w:body>
</w:document>

[您可以看到Word使用多个w:fldSimple元素和一个以“ sdtContent”作为其内容的w:fldChar元素将简单字段(w:instrText元素)变成了复杂字段。此外,您可以看到文本“错误!未定义书签”。作为字段的结果。

Word创建该错误消息是因为您的指令文本("sdtContent")不正确。如果将"sdtContent"替换为有效的字段名称,例如"AUTONUM",则不会看到该错误消息。但是,在AUTONUM的情况下,显然会得到可见场结果。为避免这种情况,可以使用REF字段,但是您需要一个有效的书签。在下面的示例中创建:

[Fact]
public void CreateSimpleFieldForAutomaticUpdate()
{
    using WordprocessingDocument wordDocument = WordprocessingDocument.Create(
        "SimpleFieldRef.docx", WordprocessingDocumentType.Document);

    MainDocumentPart part = wordDocument.AddMainDocumentPart();
    part.Document =
        new Document(
            new Body(
                new Paragraph(
                    new Run(
                        new Text("Hello World!"))),
                new BookmarkStart { Id = "32767", Name = "_RefUpdate" },
                new BookmarkEnd { Id = "32767" },
                new Paragraph(
                    new SimpleField
                    {
                        Instruction = "REF _RefUpdate",
                        Dirty = true
                    }),
                new SectionProperties()));
}

您必须编写代码,以便在您的w:bookmarkStart子元素之前插入一个BookmarkStart元素(w:bookmarkEnd类),BookmarkEnd元素(w:p类)和w:fldSimple元素。 w:sectPr元素(SectionProperties类)。在我的示例中,我使用了一个较大的整数值作为书签ID,并使用了_RefUpdate作为书签名称,这在Instruction属性中也使用了。]

© www.soinside.com 2019 - 2024. All rights reserved.