【问题标题】:How to generate Table Of Contents using OpenXML SDK 2.0?如何使用 OpenXML SDK 2.0 生成目录?
【发布时间】:2012-03-18 21:57:26
【问题描述】:

使用 SDK,我正在构建包含报告的 Word 文档。这些文件需要有TOC。 有没有人有一个完整的解决方案,我可以遵循以了解如何做到这一点?

(我已经阅读了http://openxmldeveloper.org/ 上的所有内容)

【问题讨论】:

    标签: .net openxml openxml-sdk


    【解决方案1】:

    看看 Eric White 的 Fourth and Final Screen-Cast in Series on Adding/Updating the TOC in OpenXML WordprocessingML Documents

    希望有帮助!

    更新:


    According FAQ from MSDN Forums 我看到不支持此功能:

    8) 如何在Word文档中生成TOC(目录)?

    Open XML SDK 2.0 不支持此功能。 但你可以生成 通过 Word 应用的小 TOC,并用 Document 反映 TOC 部分 Open XML SDK 生产力工具中的反射器组件,了解如何 以编程方式生成 TOC。 如需更多详细信息,请 参考:


    更新 2


    根据我们下面的 cmets,我可以建议使用这种场景:

    1. 您手动创建一个空的 DOCX 文件并在其中插入 TOC。
    2. 然后保存此文件并在 OpenXML SDK 2.0 工具中打开它,该工具为您提供了 C# 代码来生成这样的带有 TOC 占位符的空文件。
    3. 然后以编程方式将所需的所有数据刷新到此 DOCX 文件并保存。
    4. 此外,您还需要提供在刷新数据(或打开文档后)自动更新 TOC 的机制。有几个选项可以做到这一点 - 请参阅我上面提供的 Eric White 帖子链接中的屏幕截图 3-5。特别是,我认为您应该注意5th one - “展示了如何在打开任何包含 TOC 的文档时使用 AutoOpen 宏来更新 TOC”。

    所有这些看起来都有些棘手,但我希望这会有所帮助。

    【讨论】:

    • 谢谢,但链接已损坏。是this 吗?
    • 我有固定链接。而且 - 是的 - 这与在 openxmldeveloper.org 上发布的相同......经过一些研究,我用一些新的细节调整了我的答案
    • 感谢您的回复。我也阅读了大多数与 MSDN 相关的内容,但我不知道如何实现这个解决方案。此外,似乎没有人提供一个例子。毕竟,TOC 是文档的重要组成部分……我认为 OpenXML SDK 以某种方式涵盖了它(或者至少有人想出了一个可行且易于使用的解决方案)。
    • 一位来自here 的用户说得很清楚:“整个 OOXML 的东西越来越让我惊奇。唉,并不总是以积极的方式......有很大的潜力,但是文档太少了!!!我只是想使用OOXML SDK2在VS2008中输入一些代码,让Word在我的文档中重新生成(或生成,这更容易???)TOC。我一直在尝试,但似乎无法找到包的各个部分的正确位......“
    • 您能描述一下您的需求吗?也许(经常发生)你不需要你在想什么;)让我们一起尝试找出解决方法......
    【解决方案2】:

    使用自动目录(可点击)

    1. 设置标题

       public static Paragraph SetHeading1(this Paragraph p)
       {
           var pPr = p.Descendants<ParagraphProperties>().First();
           pPr.ParagraphStyleId = new ParagraphStyleId() { Val = "Heading1" };
           return p;
       }
      
    2. 从空文档生成目录,你可以使用这个:

    private static string GetTOC(string title, int titleFontSize)
        {
            return $@"<w:sdt>
         <w:sdtPr>
            <w:id w:val=""-493258456"" />
            <w:docPartObj>
               <w:docPartGallery w:val=""Table of Contents"" />
               <w:docPartUnique />
            </w:docPartObj>
         </w:sdtPr>
         <w:sdtEndPr>
            <w:rPr>
               <w:rFonts w:asciiTheme=""minorHAnsi"" w:eastAsiaTheme=""minorHAnsi"" w:hAnsiTheme=""minorHAnsi"" w:cstheme=""minorBidi"" />
               <w:b />
               <w:bCs />
               <w:noProof />
               <w:color w:val=""auto"" />
               <w:sz w:val=""22"" />
               <w:szCs w:val=""22"" />
            </w:rPr>
         </w:sdtEndPr>
         <w:sdtContent>
            <w:p w:rsidR=""00095C65"" w:rsidRDefault=""00095C65"">
               <w:pPr>
                  <w:pStyle w:val=""TOCHeading"" />
                  <w:jc w:val=""center"" /> 
               </w:pPr>
               <w:r>
                    <w:rPr>
                      <w:b /> 
                      <w:color w:val=""2E74B5"" w:themeColor=""accent1"" w:themeShade=""BF"" /> 
                      <w:sz w:val=""{titleFontSize * 2}"" /> 
                      <w:szCs w:val=""{titleFontSize * 2}"" /> 
                  </w:rPr>
                  <w:t>{title}</w:t>
               </w:r>
            </w:p>
            <w:p w:rsidR=""00095C65"" w:rsidRDefault=""00095C65"">
               <w:r>
                  <w:rPr>
                     <w:b />
                     <w:bCs />
                     <w:noProof />
                  </w:rPr>
                  <w:fldChar w:fldCharType=""begin"" />
               </w:r>
               <w:r>
                  <w:rPr>
                     <w:b />
                     <w:bCs />
                     <w:noProof />
                  </w:rPr>
                  <w:instrText xml:space=""preserve""> TOC \o ""1-3"" \h \z \u </w:instrText>
               </w:r>
               <w:r>
                  <w:rPr>
                     <w:b />
                     <w:bCs />
                     <w:noProof />
                  </w:rPr>
                  <w:fldChar w:fldCharType=""separate"" />
               </w:r>
               <w:r>
                  <w:rPr>
                     <w:noProof />
                  </w:rPr>
                  <w:t>No table of contents entries found.</w:t>
               </w:r>
               <w:r>
                  <w:rPr>
                     <w:b />
                     <w:bCs />
                     <w:noProof />
                  </w:rPr>
                  <w:fldChar w:fldCharType=""end"" />
               </w:r>
            </w:p>
         </w:sdtContent>
      </w:sdt>"
            }
    
    1. 创建SdtBlock,并设置TOC xml

           var sdtBlock = new SdtBlock();
           sdtBlock.InnerXml = GetTOC(Translations.ResultsBooksTableOfContentsTitle, 16);
           document.MainDocumentPart.Document.Body.AppendChild(sdtBlock);
      
    2. 设置 UpdateFieldsOnOpen

           var settingsPart = document.MainDocumentPart.AddNewPart<DocumentSettingsPart>();
           settingsPart.Settings = new Settings { BordersDoNotSurroundFooter = new BordersDoNotSurroundFooter() { Val = true } };
      
           settingsPart.Settings.Append(new UpdateFieldsOnOpen() { Val = true });
      

    如果您需要从 docx 生成 pdf 文件,它工作正常!

    【讨论】:

    • 像魅力一样工作。修复了代码块,因为它留下了几个标签
    【解决方案3】:

    感谢Dmitri Pavlov (@DmitryPavlov) 的帮助。

    我不想回答我自己的问题,但这只是为了说明我已采取的步骤。

    对任何感兴趣的人的建议是观看由 Eric White -Exploring Tables-of-Contents in Open XML WordprocessingML Documents 制作的 5 部分截屏。这包含有关添加和更新 TOC 的所有信息(还有更多)。

    我的解决方案是使用模板(只是一个常规的空文档,其中包含我需要的所有样式:标题 1-5、TOC 样式等)。这对于快速修复样式问题特别有用(具有 TOC 的新文档将创建一个新的 style.xml;此文件有一些额外的数据;因此 TOC 中的层次结构不是预期 - 即,标题 2 是标题 1 的子节点,标题 3 是标题 2 的子节点,等等)。

    因此:

    1. 创建一个 Word 文档并添加您希望以后以编程方式添加的所有元素(例如,标题 1-5、目录等)。删除所有内容并保存文档(这样做的原因是为所有必要的元素创建样式)。

    2. 我亲自将模板(在步骤 #1 中创建的文件)作为资源添加到我的项目中。

    3. 在您的代码中,创建模板的新副本(这将是您将处理的实际文件)。我用过:

      byte[] stream = Properties.Resources.Template;
      File.WriteAllBytes(@"D:\Template.docx", stream);
      File.Copy(@"D:\Template.docx", @"D:\New.docx");
      
    4. 将所有数据刷新到此文档。

    5. 将来自截屏 2、3 或 4 的源文件添加到您的项目中(有关此内容,请参阅截屏 3)- 在这些帖子的末尾,您会找到一个下载链接 TocAdder .zip。或者只是添加对 TocAdder.dll 的引用。

    6. 插入目录。只是一个例子:

      using (WordprocessingDocument wdoc = WordprocessingDocument.Open(@"D:\New.docx", true))
      {
          XElement firstPara = wdoc
              .MainDocumentPart
              .GetXDocument()
              .Descendants(W.p)
              .FirstOrDefault();
          TocAdder.AddToc(wdoc, firstPara,
              @"TOC \o '1-3' \h \z \u", null, null);
      }
      
    7. 用模板中的样式替换新创建的文档中的样式。您可以使用 MSDN 中的此资源:Replacing the Styles Parts in Word 2010 Documents by Using the Open XML SDK 2.0。再举个例子:

      string fromDoc = @"D:\Template.docx";
      string toDoc = @"D:\New.docx";
      var node = WDExtractStyles(fromDoc, false);
      if (node != null)
          WDReplaceStyles(toDoc, node, false);
      node = WDExtractStyles(fromDoc);
      if (node != null)
          WDReplaceStyles(toDoc, node);
      
    8. 可以选择使用截屏 3、4 或 5 中描述的方法之一,以解决 Word 提出的模式对话框问题。

    希望这对某人有用。

    【讨论】:

    • 当您使用流而不是文件时,是否也可以删除模式对话框?因为我正在使用memorystream生成一个文档,然后提供给用户下载。现在他们必须单击“是”来更新目录,因为我找不到避免这种模式对话框的方法。
    【解决方案4】:

    如果您有 TOC 字段,这将导致在 Word 中打开文档时更新它(body 是对文档正文的引用):

    DocumentFormat.OpenXml.Wordprocessing.SimpleField f;
    f = new SimpleField();
    f.Instruction="sdtContent";
    f.Dirty = true;
    body.Append(f);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-09
      • 2010-11-03
      • 2012-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-27
      • 1970-01-01
      相关资源
      最近更新 更多