将 MergeField 更改为纯文本

Change MergeField to text only

我需要将文本替换为 MergeField,并且只是简单的文本。我发现 on the topic. It works for me. This code changes the text, but leaves the field as MergeField. And other questionMergeField 更改为文本。但如果一行中有多个这样的字段,则第二个将被删除。

此时,我对第一个 link 中的代码进行了一些调整。我需要添加什么才能将 MergeField 更改为文本?

string sourceFile = @"C:\Users\Owl\Desktop\Template.docm";
string targetFile = @"C:\Users\Owl\Desktop\Result.docx";
File.Copy(sourceFile, targetFile, true);
using (WordprocessingDocument document = WordprocessingDocument.Open(targetFile, true))
{
    document.ChangeDocumentType(WordprocessingDocumentType.Document);

    foreach (FieldCode field in document.MainDocumentPart
                                        .RootElement.Descendants<FieldCode>())
    {
        int indexEndName = field.Text.IndexOf("\");
        string fieldName = string.Format("«{0}»", 
                                  field.Text.Substring(11, indexEndName - 11).Trim());

        foreach (Run run in document.MainDocumentPart.Document.Descendants<Run>())
        {
            foreach (Text txtFromRun in run.Descendants<Text>()
                                           .Where(a => a.Text == fieldName))
            {
                txtFromRun.Text = "some text";
            }
        }
    }

    document.MainDocumentPart.Document.Save();
}

更新

我错了。第二个代码link。该行中的第二个字段未删除。它留下来。但不落入循环,被忽略。我不明白为什么。

问题

topic 中的代码仅在 MergeField 位于不同段落中时有效。如果有多个段落,则只处理第一个MergeField。其余忽略不计。

这是因为删除了父元素。

Run rFldCode = (Run)field.Parent; 
...
rFldCode.Remove();

foreach 的下一个元素将来自下一段。我的意思是我的问题代码的第一个循环。

解决方案

收集 ListMergeField 的所有部分。

Run rFldParent = (Run)field.Parent;
List<Run> runs = new List<Run>();

runs.Add(rFldParent.PreviousSibling<Run>()); // begin
runs.Add(rFldParent.NextSibling<Run>()); // separate
runs.Add(runs.Last().NextSibling<Run>()); // text
runs.Add(runs.Last().NextSibling<Run>()); // end

图片清晰。这对我的理解帮助很大。

现在删除这些项目

foreach(Run run in runs)
{
    run.Remove();
}

以及文本字段<w:instrText xml:space="preserve"> MERGEFIELD...

field.Remove(); // instrText

并添加新文本

rFldParent.Append(new Text(replacementText));

现在,MergeField 不再只是文本。

完整代码

string sourceFile = @"C:\Users\Owl\Desktop\Template.docm";
string targetFile = @"C:\Users\Owl\Desktop\Result.docx";
File.Copy(sourceFile, targetFile, true);
using (WordprocessingDocument document = WordprocessingDocument.Open(targetFile, true))
{
    document.ChangeDocumentType(WordprocessingDocumentType.Document);

    foreach (FieldCode field in document.MainDocumentPart.RootElement.Descendants<FieldCode>())
    {
        ReplaceMergeFieldWithText(field, "some text");
    }

    document.MainDocumentPart.Document.Save();
}

private void ReplaceMergeFieldWithText(FieldCode field, string replacementText)
{
    if (field == null || replacementText == string.Empty)
    {
        return;
    }

    Run rFldParent = (Run)field.Parent;
    List<Run> runs = new List<Run>();

    runs.Add(rFldParent.PreviousSibling<Run>()); // begin
    runs.Add(rFldParent.NextSibling<Run>()); // separate
    runs.Add(runs.Last().NextSibling<Run>()); // text
    runs.Add(runs.Last().NextSibling<Run>()); // end

    foreach(Run run in runs)
    {
        run.Remove();
    }

    field.Remove(); // instrText
    rFldParent.Append(new Text(replacementText));
}

奖金

要插入不同的值,您必须创建 Dictionary。其中键是 MergeField 名称,值是要插入的文本。

缩短字段名称

int indexEndName = field.Text.IndexOf("\");
string fieldName = field.Text.Substring(11, indexEndName - 11).Trim();

例如

Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("key 1", "value 1");
dict.Add("key 2", "value 2");
dict.Add("key 3", "value 3");

...

foreach (FieldCode field in document.MainDocumentPart.RootElement.Descendants<FieldCode>())
{
    int indexEndName = field.Text.IndexOf("\");
    string fieldName = field.Text.Substring(11, indexEndName - 11).Trim();

    ReplaceMergeFieldWithText(field, dict[fieldName]);
}