替换文本框的内部文本

本文关键字:文本 内部 替换 | 更新日期: 2023-09-27 18:32:50

使用 MS OpenXml Sdk,我已经能够将模板流复制到结果流中,并使用以下代码在正文末尾附加动态文本 (w.p>>w.r>>w.t(:

var templateStream = File.OpenRead(templatePath);
templateStream.CopyTo(resultStream);
using (var resultPackage = WordprocessingDocument.Open(resultStream, true))
{
     var document = resultPackage.MainDocumentPart.Document;
     var body = document.Body;
     // Add new text.
     var para = body.AppendChild(new Paragraph());
     var run = para.AppendChild(new Run());
     run.AppendChild(new Text(firstName));
     document.Save();
}

我的下一个合乎逻辑的步骤是将 resultStream 中文本框的内部文本替换为 firstName,如下面的代码所示。

// replacing code in using statement from above
var document = resultPackage.MainDocumentPart.Document;
var textbox = document.Descendants<TextBox>().First();
const string firstNametag = "<<IH.FirstName>>";
if (textbox.InnerText.Contains(firstNametag))
{
   var textboxContent = textbox.Elements<TextBoxContent>().First();
   textboxContent.RemoveAllChildren();
   var paragraph = textboxContent.AppendChild(new Paragraph());
   var run = paragraph.AppendChild(new Run());
   run.AppendChild(new Text(firstName));
}
document.Save();

在第一个示例中,使用一些附加代码,结果流被适当地序列化为 docx,并且在 Word 中查看时,firstName 将附加到正文的末尾。 在第二个示例中,尽管文本框及其内容保持不变,即使调试器中的进一步检查显示 textboxContent 的子项反映了上述所做的更改。

我是OpenXML开发的新手,所以如果有任何明显的东西,请指出来。

替换文本框的内部文本

哦,哇,我什至不想认为我了解围绕此的整个情况,但这里有一个快速的尝试。 具有更多开放XML经验的人请插话...

事实证明,当您在文档.xml文档上的word中创建文本框时,文件将获得以下标记:

<w.r>
    <mc.AlertnateContent>
        <mc.Choice Requires="wps">
            <wps:txbx>
                <w:txbxContent>
                    <w:r>
                        <w.t>
                            Text Goes Here
                        </w.t>
                    </w.r>
                </w:txbxContent>
            </wps:txbx>
        </mc.Choice>
        <mc.Fallback>
            <v.textbox>
                <w:txbxContent>
                    <w:r>
                        <w.t>
                            Text Goes Here
                        </w.t>
                    </w.r>
                </w:txbxContent>
            </v.textbox>
        </mc.Fallback>
    </mc.AlertnateContent>
</w.r>

请注意 mc.AlternateContent、mc.Choice 和 mc.Fallback 标签。 这些到底是什么???有人在我看到的一篇博客文章中这样说——

"据我了解 - 但不要把我的话当作福音 - 替代内容可以出现在任何位置,并提供一种机制来包含增强功能(如果消费应用程序可以处理它(,以及如果不能,请后退。-托尼·乔兰斯 - http://social.msdn.microsoft.com/Forums/en-US/worddev/thread/f8a5c277-7049-48c2-a295-199d2914f4ba/

就我而言,我只是修改了回退文本框(v.txbx 而不是 wps.txbx(,因为我在假设 Resharper 要求我导入 DocumentFormat.OpenXml.Vml 命名空间以依赖 TextBox 对象时犯了错误。 不知道为什么在我已经包含的命名空间之一中没有文本框定义,DocumentFormat.OpenXml.Packaging 或 DocumentFormat.OpenXml.Wordprocessing,但这超出了这个问题的范围。 不用说,在意识到这一点并更新我的代码以查找两个共同的 w.txbxContent 后,我实现了我想做的事情。

下面是经过一些重构的更新代码,在原始问题的 using 语句中调用 ReplaceTag 方法,并提供模型对象而不是字符串。 另外,为方便起见,请使用 tagToValueSelector 字典。

private void ReplaceTags(Document document, SomeModel model)
{
    var textBoxContents = document.Descendants<TextBoxContent>().ToList();
    foreach (var textBoxContent in textBoxContents)
    {
        ReplaceTag(textBoxContent, model);
    }
}
private void ReplaceTag(TextBoxContent textBoxContent, SomeModel model)
{
    var tag = textBoxContent.InnerText.Trim();
    if (!tagsTomValues.ContainsKey(tag)) return;
    var valueSelector = tagsTomValues[tag];
    textBoxContent.RemoveAllChildren();
    var paragraph = textBoxContent.AppendChild(new Paragraph());
    var run = paragraph.AppendChild(new Run());
    run.AppendChild(new Text(valueSelector(model)));
}
// called in the ctor
private static void IntializeTags(IDictionary<string, Func<SomeModel, string>> dictionary)
{
    dictionary.Add("<<IH.Name>>", m => string.Format("{0} {1}", m.FirstName, m.LastName));
}

快乐开放Xmling :)