如何使用OpenXML SDK 2.0生成目录?

时间:2012-03-18 21:57:27

标签: .net openxml openxml-sdk

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

(我已阅读http://openxmldeveloper.org/

上的所有内容

4 个答案:

答案 0 :(得分:9)

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

希望有所帮助!

更新:


来自MSDN论坛的

According FAQ我发现不支持此功能:

  

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

     

Open XML SDK 2.0不支持此功能。 但您可以生成   通过Word应用程序进行小型TOC,并使用Document反映TOC部分   Open XML SDK Productivity Tool中的Reflector组件,以了解如何操作   以编程方式生成TOC。 有关详细信息,请   参考:


更新2


根据我们以下的评论,我可以建议使用这种情况:

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

答案 1 :(得分:5)

使用自动目录(可单击)

  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>
    

    ”         }

  3. 创建SdtBlock,并设置TOC xml

        var sdtBlock = new SdtBlock();
        sdtBlock.InnerXml = GetTOC(Translations.ResultsBooksTableOfContentsTitle, 16);
        document.MainDocumentPart.Document.Body.AppendChild(sdtBlock);
    
  4. 设置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文件,则可以正常工作!

答案 2 :(得分:3)

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

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

对任何感兴趣的人的建议是观看由Eric White制作的5部分剧本 - Exploring Tables-of-Contents in Open XML WordprocessingML Documents。这包含有关添加和更新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. 插入TOC。举个例子:

    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提出的模式对话框的问题。

  9. 希望这对某些人有用。

答案 3 :(得分:1)

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

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