【发布时间】:2012-03-18 21:57:26
【问题描述】:
使用 SDK,我正在构建包含报告的 Word 文档。这些文件需要有TOC。 有没有人有一个完整的解决方案,我可以遵循以了解如何做到这一点?
(我已经阅读了http://openxmldeveloper.org/ 上的所有内容)
【问题讨论】:
标签: .net openxml openxml-sdk
使用 SDK,我正在构建包含报告的 Word 文档。这些文件需要有TOC。 有没有人有一个完整的解决方案,我可以遵循以了解如何做到这一点?
(我已经阅读了http://openxmldeveloper.org/ 上的所有内容)
【问题讨论】:
标签: .net openxml openxml-sdk
看看 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,我可以建议使用这种场景:
所有这些看起来都有些棘手,但我希望这会有所帮助。
【讨论】:
使用自动目录(可点击)
设置标题
public static Paragraph SetHeading1(this Paragraph p)
{
var pPr = p.Descendants<ParagraphProperties>().First();
pPr.ParagraphStyleId = new ParagraphStyleId() { Val = "Heading1" };
return p;
}
从空文档生成目录,你可以使用这个:
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>"
}
创建SdtBlock,并设置TOC xml
var sdtBlock = new SdtBlock();
sdtBlock.InnerXml = GetTOC(Translations.ResultsBooksTableOfContentsTitle, 16);
document.MainDocumentPart.Document.Body.AppendChild(sdtBlock);
设置 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 文件,它工作正常!
【讨论】:
感谢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 的子节点,等等)。
因此:
创建一个 Word 文档并添加您希望以后以编程方式添加的所有元素(例如,标题 1-5、目录等)。删除所有内容并保存文档(这样做的原因是为所有必要的元素创建样式)。
我亲自将模板(在步骤 #1 中创建的文件)作为资源添加到我的项目中。
在您的代码中,创建模板的新副本(这将是您将处理的实际文件)。我用过:
byte[] stream = Properties.Resources.Template;
File.WriteAllBytes(@"D:\Template.docx", stream);
File.Copy(@"D:\Template.docx", @"D:\New.docx");
将所有数据刷新到此文档。
将来自截屏 2、3 或 4 的源文件添加到您的项目中(有关此内容,请参阅截屏 3)- 在这些帖子的末尾,您会找到一个下载链接 TocAdder .zip。或者只是添加对 TocAdder.dll 的引用。
插入目录。只是一个例子:
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);
}
用模板中的样式替换新创建的文档中的样式。您可以使用 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);
可以选择使用截屏 3、4 或 5 中描述的方法之一,以解决 Word 提出的模式对话框问题。
希望这对某人有用。
【讨论】:
如果您有 TOC 字段,这将导致在 Word 中打开文档时更新它(body 是对文档正文的引用):
DocumentFormat.OpenXml.Wordprocessing.SimpleField f;
f = new SimpleField();
f.Instruction="sdtContent";
f.Dirty = true;
body.Append(f);
【讨论】: