OpenXml: обновление содержания дает ошибку! Закладка не определена - PullRequest
0 голосов
/ 31 октября 2019

Я работаю над утилитой OpenXml для динамического добавления содержимого в текстовый документ, а затем хочу обновить оглавление.

        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());

Я добавил SimpleField в документ с набором Dirtyк истине. Когда я открываю сгенерированный файл, он показывает ниже подтверждающее сообщение, чтобы обновить оглавление. Нажатие Да корректно обновляет содержание.

enter image description here

Но проблема в том, что Ошибка! Закладка не определена. текст добавляется внизу документа.

Любая идея, как удалить это сообщение об ошибке с работающей функцией обновления оглавления.

1 Ответ

0 голосов
/ 02 ноября 2019

Я понимаю, что вы пытаетесь сделать, это вставить грязный элемент w:fldSimple (класс SimpleField) в ваш документ, чтобы Word обновил все поля, включая оглавление, как только пользователь откроет этот документ с помощью Microsoft Word,Однако, если вы посмотрите на разметку Open XML, созданную Microsoft Word после обновления полей, вы увидите, что ваш 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)) в сложное поле, используя несколько элементов w:fldChar и один элемент w:instrText, имеющий в качестве содержимого sdtContent. Далее вы можете увидеть текст «Ошибка! Закладка не определена». как результат поля.

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). В моем примере я использовал большое целочисленное значение в качестве идентификатора закладки и _RefUpdate в качестве имени закладки, которое также используется в свойстве Instruction.

...