使用OpenXML将RTF和HTML插入Rich Text Box内容控件

时间:2014-08-28 08:47:41

标签: c# ms-word openxml openxml-sdk

我在Word模板中有一个富文本框contentControl。我正在尝试将RTF数据插入ContentControl并从中生成word文档。我按照here告诉AltChunk。这适用于SdtBlock。由于SdtBlock的父级是Body,我们可以直接将AltChunk插入到正文中。如果word文档有多个富文本框contentControls,则word将控件保存为SdtRunSdtRun的父级为Paragraph,其父级为Body。如果我们尝试做类似

的事情
SdtRun contentControl = (SdtRun)wordprocessingDocument.MainDocumentPart.RootElement.Descendants<SdtRun>().FirstOrDefault(x => x.Descendants<Tag>().Any(y => y.Val == "richtextbox")); 

contentControl.Parent.Parent.InsertAfter(altChunk, contentControl); //contentControl.Parent.Parent - Returns body of document

抛出异常 由于对象的当前状态,操作无效

所以我尝试使用Paragraph

Paragraph contentControl = (Paragraph)wordprocessingDocument.MainDocumentPart.RootElement.Descendants<Paragraph>().FirstOrDefault(x => x.Descendants<Tag>().Any(y => y.Val == "richtextbox"));
contentControl.Parent.InsertAfter(altChunk, contentControl); //contentControl.Parent - Returns body of document

此代码以RTF格式插入数据。但问题是我无法插入Rich TextControl的正确位置,因为我们在Paragraph上操作。

完整代码发布在

下面
 string templatePath = @"Template1.docx";
 string newFile = @"Template1_Processed.docx";

 System.IO.File.Copy(templatePath, newFile, true);

 using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(newFile, true))
    {
        Paragraph sdtElement = (Paragraph)wordprocessingDocument.MainDocumentPart.RootElement.Descendants<Paragraph>().FirstOrDefault(x => x.Descendants<Tag>().Any(y => y.Val == "richtextbox"));
        string innerText = @"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset0 Microsoft Sans Serif;}}{\colortbl ;\red139\green0\blue0;}\viewkind4\uc1\pard\cf1\f0\fs24 test\par}";
        string altChunkId = "myId";
        MainDocumentPart mainDocPart = wordprocessingDocument.MainDocumentPart;
        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(innerText));

        // Create alternative format import part.
        AlternativeFormatImportPart formatImportPart =
            mainDocPart.AddAlternativeFormatImportPart(
                AlternativeFormatImportPartType.Rtf, altChunkId);

        // Feed HTML data into format import part (chunk).
        formatImportPart.FeedData(ms);
        AltChunk altChunk = new AltChunk();
        altChunk.Id = altChunkId;

        sdtElement.Parent.InsertAfter<AltChunk>(altChunk, sdtElement);
        SdtElement contentControl = (SdtElement)wordprocessingDocument.MainDocumentPart.RootElement.Descendants<SdtElement>().FirstOrDefault(x => x.Descendants<Tag>().Any(y => y.Val == "richtextbox"));
        contentControl.Remove();
        wordprocessingDocument.MainDocumentPart.CreateRelationshipToPart(formatImportPart);

        sdtElement = (Paragraph)wordprocessingDocument.MainDocumentPart.RootElement.Descendants<Paragraph>().FirstOrDefault(x => x.Descendants<Tag>().Any(y => y.Val == "richtextbox1"));
        if (sdtElement != null)
        {
            innerText = @"<html><head></head><body><h1>HELLO</h1></body></html>";
            altChunkId = "myId1";
            ms = new MemoryStream(Encoding.UTF8.GetBytes(innerText));

            // Create alternative format import part.
            formatImportPart =
                mainDocPart.AddAlternativeFormatImportPart(
                    AlternativeFormatImportPartType.Html, altChunkId);

            // Feed HTML data into format import part (chunk).
            formatImportPart.FeedData(ms);
            altChunk = new AltChunk();
            altChunk.Id = altChunkId;
            sdtElement.Parent.InsertAfter(altChunk, sdtElement);
            contentControl = (SdtElement)wordprocessingDocument.MainDocumentPart.RootElement.Descendants<SdtElement>().FirstOrDefault(x => x.Descendants<Tag>().Any(y => y.Val == "richtextbox1"));
            contentControl.Remove();

            wordprocessingDocument.MainDocumentPart.CreateRelationshipToPart(formatImportPart);

            wordprocessingDocument.MainDocumentPart.Document.Save();
            wordprocessingDocument.Close();
        }
    }

附加模板的屏幕截图 enter image description here并生成word文档 enter image description here

由于我们在Paragraph之后插入,因此它会在Paragraph旁边插入。因此,我们无法将数据插入到文档中存在富文本数据的正确位置。

有人可以帮我解决这个问题/建议任何其他方法来实现吗?

2 个答案:

答案 0 :(得分:0)

docx4j实现了内容控制数据绑定的一些约定,称为&#34; OpenDoPE&#34;。 (我对这个名字负责,还有更多......)

OpenXML允许您通过XPath表达式将内容控件绑定到XML元素(在CustomXML数据部分中)。

使用OpenDoPE,该XML元素可以包含转义的XHTML,而docx4j会自动将该XHTML转换为真正的Word内容。

版本为docx4j for .NET on Nuget

答案 1 :(得分:0)

您要做的不是altChunk的功能。 altChunk只能在块级别插入内容,而不能在运行级别插入内容。此外,您可以做很少的事情来影响altChunk内容的处理。 Word(或Word Automation Services)可以完成它所做的工作,而且你无法改变它。

您是导入RTF的唯一选择吗?您是否有其他可能的格式,例如XHTML或?

我想到了一个非常奇怪的想法 - 如果您在要导入RTF的位置插入文本框怎么办?我很确定你可以在文本框中导入 - 事实上,你会在块级别导入内容。您可以创建一个随文本移动的内嵌文本框。虽然不是超级简单,但您也可以影响相对于文本显示文本框的位置。根据您的实际情况,这可能是可能的。

如果要导入HTML,可以选择在适当的位置将HTML转换为WordprocessingML。这更可行。我不知道任何将RTF转换为WordprocessingML的工具(虽然这听起来像一个有趣的项目!)

-Eric