Office Open XML SDK 文字替换

4
为了基于来自SQL数据库的数据创建Word文档,我使用Office Open XML SDK来避免使用互操作性。这加快了过程并消除了在客户端系统上安装Microsoft Office套件的要求。
虽然这很有效,但我在替换文档中某些文本时遇到了问题。为了使最终文档的定制成为一种选择,我创建了一个带有标记的文档作为模板。此模板包含诸如[TagHere]之类的标记。由于标记名称应易于阅读,因此我用括号[]将标记括起来,以便在整个文档中使用。
这很有效,但有时会出现问题。当您在docx文档中输入时,文本可以分成多个标记,即使在同一个单词中也是如此。像[TagHere]这样的标记可以分成 [TagHere] 当发生这种情况时,替换将无法正常工作。
现在docx格式有一些替代选项来执行此类操作,例如内容控件,但这使得创建模板的过程更加复杂。此外,在这些文档中,通常会将表格的一行标记复制多次,这可能会破坏内容标记原则。因此,我选择不使用此选项。
如果有人能解决这个问题,那将是很好的。

如果您将该内容放入代码部分,则无需更换钓鱼钩(=尖括号):选择文本,然后单击“101010”按钮。 - LarsH
感谢您的评论,每天都在学习 :) - Cpt. eMco
1个回答

4

不要输入纯文本“taghere”,而是插入合并字段。(在Word中,点击“插入”>“快速部件”>“字段”。选择“MergeField”,并在“字段名称”字段中输入“TagHere”)

然后,不要进行文本查找替换,而是扫描文档以查找合并字段并设置其内部文本。

class Program
{
    static void Main(string[] args)
    {
        string document = args[0];
        using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
        {
            Dictionary<string, string> replaceOperations = new Dictionary<string, string>();

            replaceOperations.Add("company", "alex's applications");
            replaceOperations.Add("first_name", "alexander");
            replaceOperations.Add("last_name", "taylor");
            //etc

            Replace(wordDoc, replaceOperations);
        }
    }

    public static char[] splitChar = new char[] {' '};
    public static void Replace(WordprocessingDocument document, Dictionary<string, string> replaceOperations)
    {
        //find all the fields
        foreach (var field in document.MainDocumentPart.Document.Body.Descendants<SimpleField>())
        {
            //parse the instruction
            string[] instruction = field.Instruction.Value.Split(splitChar, StringSplitOptions.RemoveEmptyEntries);

            //check if it's a merge field, and if so...
            if (instruction[0].ToLower().Equals("mergefield"))
            {
                //get the field name
                string fieldname = instruction[1];

                //find the text inside (there will only be one)
                foreach (var fieldtext in field.Descendants<Text>())
                {
                    //see if we know what to set this value to
                    string value = replaceOperations.ContainsKey(fieldname) ? replaceOperations[fieldname] : null;

                    //if we found the replace value, set the text to this value
                    if (value != null)
                        fieldtext.Text = value;

                    //should only be one text inside
                    break;
                }
            }
        }
    }
}

1
我正在尝试类似的事情,但问题在于合并域并不总是表示为“SimpleField”,有时它们是带有相关“FieldChar”的“FieldCode”。 - Matt Burland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接