我有一个带有一些控制占位符的单词模板。它包含表内容和一些其他信息。
在页面中,我设置了一些控制占位符,我想在这些位置插入来自休息服务的新文本。如果其余服务返回数据(对象)数组,则需要基于单词模板在每个页面中复制信息。
任何想法我该如何使用documentformat.openxml来做到这一点?
编辑:
我在这里找到了这个[[post,这很好,但是我不知道如何将数据数组应用于同一模板的多个页面。
所以,如何在新文档中从同一模板创建多个页面?数据作为数组输入。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
个元素)。