使用documentformat.openxml从具有多个页面的Word模板创建新文档

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

我有一个带有一些控制占位符的单词模板。它包含表内容和一些其他信息。

在页面中,我设置了一些控制占位符,我想在这些位置插入来自休息服务的新文本。如果其余服务返回数据(对象)数组,则需要基于单词模板在每个页面中复制信息。

任何想法我该如何使用documentformat.openxml来做到这一点?

编辑:

我在这里找到了这个[[post,这很好,但是我不知道如何将数据数组应用于同一模板的多个页面。

所以,如何在新文档中从同一模板创建多个页面?数据作为数组输入。
ms-word openxml openxml-sdk
1个回答
1
投票
下面的示例代码(可编译但未经单元测试)完成了您要实现的目标。它基于对问题和假设的以下解释:

    “控件占位符”表示“富文本内容控件”,在Open XML术语中称为块级内容控件,因此由Open XML SDK中的SdtBlock类表示。
  • 内容控件具有标签,这意味着相关的w:sdt元素具有类似<w:tag="tagValue" />的孙元素。这些标签用于将从REST服务接收的数据链接到内容控件。
  • 数据作为Dictionary<string, string>提供,将标签值映射到内容控制文本(数据)。
  • 一般方法是对WordprocessingDocument的主文档部分执行纯功能转换。 void WriteContentControls(WordprocessingDocument)方法包装最外面的纯函数转换object TransformDocument(OpenXmlElement)。后者使用内部纯函数转换object TransformSdtBlock(OpenXmlElement, string)

    public class ContentControlWriter { private readonly IDictionary<string, string> _contentMap; /// <summary> /// Initializes a new ContentControlWriter instance. /// </summary> /// <param name="contentMap">The mapping of content control tags to content control texts. /// </param> public ContentControlWriter(IDictionary<string, string> contentMap) { _contentMap = contentMap; } /// <summary> /// Transforms the given WordprocessingDocument by setting the content /// of relevant block-level content controls. /// </summary> /// <param name="wordDocument">The WordprocessingDocument to be transformed.</param> public void WriteContentControls(WordprocessingDocument wordDocument) { MainDocumentPart part = wordDocument.MainDocumentPart; part.Document = (Document) TransformDocument(part.Document); } private object TransformDocument(OpenXmlElement element) { if (element is SdtBlock sdt) { string tagValue = GetTagValue(sdt); if (_contentMap.TryGetValue(tagValue, out string text)) { return TransformSdtBlock(sdt, text); } } return Transform(element, TransformDocument); } private static object TransformSdtBlock(OpenXmlElement element, string text) { return element is SdtContentBlock ? new SdtContentBlock(new Paragraph(new Run(new Text(text)))) : Transform(element, e => TransformSdtBlock(e, text)); } private static string GetTagValue(SdtElement sdt) => sdt .Descendants<Tag>() .Select(tag => tag.Val.Value) .FirstOrDefault(); private static T Transform<T>(T element, Func<OpenXmlElement, object> transformation) where T : OpenXmlElement { var transformedElement = (T) element.CloneNode(false); transformedElement.Append(element.Elements().Select(e => (OpenXmlElement) transformation(e))); return transformedElement; } }

    即使细节有所不同(例如,有关如何将数据数组映射到特定内容控件的信息,这也应提供足够的输入来实施您的特定解决方案。此外,如果您不使用块级结构化文档标签([ SdtBlock,Rich Text内容控件),而是内联级别的结构化文档标签(SdtRun,纯文本内容控件),原理是相同的,而不是[[]中包含的Paragraph实例(w:p元素) C0]个实例,您将在SdtContentBlock个实例中包含Run个实例(w:r个元素)。
  • © www.soinside.com 2019 - 2024. All rights reserved.