如何用特殊字符替换XML文档中的文本?

时间:2013-08-26 13:41:55

标签: c# xml openxml opendocument

请查看此帖子的结尾,了解文本框中的问题!

使用这种方法,我想打开一个文档,替换一些文本然后不管它。 它有效,这值得骄傲。 :d

public static void replaceInOpenXMLDocument(string pfad, string zuErsetzen, string neuerString)
        {
            using (WordprocessingDocument doc = WordprocessingDocument.Open(pfad, true))
            {
                var res = from bm in doc.MainDocumentPart.Document.Body.Descendants()
                          where bm.InnerText != string.Empty && bm.InnerText.Contains(zuErsetzen) && bm.HasChildren == false
                          select bm;

                foreach (var item in res)
                {
                    item.InsertAfterSelf(new Text(item.InnerText.Replace(zuErsetzen, neuerString)));
                    item.Remove();
                }
                doc.Close();
            }
        }

但它只适用于替换没有特殊字符的 。 例如:

操作系统将替换为 Windows 9000

[OS] 将保持不变。

案例1:

在文件中:

  

您可以将os用于任何目的。

replaceInOpenXMLDocument("C:\NSA\suspects.docx", "os", "Win 2000");

会导致这个:

  

您可以将Win 2000用于任何目的。

案例2:

有特殊的字符......

  

你将[os]用于任何目的。

replaceInOpenXMLDocument("C:\NSA\suspects.docx", "[os]", "Win 2000");

......它只是忽略了我:

  

你将[os]用于任何目的。

我尝试了几个特殊字符()[] {} 等,但它们永远不会被替换。

有什么我忘了做的吗?或者它是否根本无法用这种方法替换特殊字符? 如果是这样,我只需要一个简单的解决方法。

有没有人帮忙解决我的绝望? :)

解决方案/补充1:

感谢Flowerking!这是我现在正在使用的代码:

public static void replaceInOpenXMLDocument(string pfad, string zuErsetzen, string neuerString)
        {
            using (WordprocessingDocument doc = WordprocessingDocument.Open(pfad, true))
            {
                SimplifyMarkupSettings settings = new SimplifyMarkupSettings
                {
                    NormalizeXml = true, // Merges Run's in a paragraph with similar formatting

                };
                MarkupSimplifier.SimplifyMarkup(doc, settings);

                //zuErsetzen = new XElement("Name", zuErsetzen).Value;
                var res = from bm in doc.MainDocumentPart.Document.Body.Descendants()
                          where bm.InnerText != string.Empty && bm.InnerText.Contains(zuErsetzen) && bm.HasChildren == false
                          select bm;
                // bm.InnerText.Contains(zuErsetzen)

                foreach (var item in res)
                {
                    item.InsertAfterSelf(new Text(item.InnerText.Replace(zuErsetzen, neuerString)));
                    item.Remove();
                }

                doc.Close();
            }
        }

(此代码适用于包含普通文本的普通文档!)

解决方案/补充2: 如果您要替换文本框中的文字,我必须做一些解决方法。 文本框被声明为图片,因此上面的代码不会触及它。

我发现了一个额外的类(link)甚至可以通过文本框进行搜索。 ZIP下载包含一个易于理解的exmaple程序。

1 个答案:

答案 0 :(得分:2)

这种情况正在发生,因为当文本包含特殊字符时,Open XML字通常会创建:

  <w:r w:rsidRPr="00316587">
    <w:rPr>
      <w:rFonts w:ascii="Consolas" w:hAnsi="Consolas" w:eastAsia="Times New Roman" w:cs="Consolas" />
      <w:color w:val="823125" />
      <w:sz w:val="20" />
      <w:szCs w:val="20" />
      <w:lang w:eastAsia="en-GB" />
    </w:rPr>
    <w:t>[</w:t>
  </w:r>
  <w:proofErr w:type="gramStart" />
  <w:r w:rsidRPr="00316587">
    <w:rPr>
      <w:rFonts w:ascii="Consolas" w:hAnsi="Consolas" w:eastAsia="Times New Roman" w:cs="Consolas" />
      <w:color w:val="823125" />
      <w:sz w:val="20" />
      <w:szCs w:val="20" />
      <w:lang w:eastAsia="en-GB" />
    </w:rPr>
    <w:t>text-to-replace</w:t>
  </w:r>
  <w:proofErr w:type="gramEnd" />
  <w:r w:rsidRPr="00316587">
    <w:rPr>
      <w:rFonts w:ascii="Consolas" w:hAnsi="Consolas" w:eastAsia="Times New Roman" w:cs="Consolas" />
      <w:color w:val="823125" />
      <w:sz w:val="20" />
      <w:szCs w:val="20" />
      <w:lang w:eastAsia="en-GB" />
    </w:rPr>
    <w:t>]</w:t>
  </w:r>
</w:p>

以上显示为文本[text-to-replace]创建的打开xml。 (请注意,情况可能并非总是如此,可能取决于您使用的客户)。

根据您的代码doc.MainDocumentPart.Document.Body.Descendants()的外观,您将整个文档的所有OpenXmlPart类型的后代占用,并尝试将逐个替换的文本替换为实际的文本在一个部分中,特殊字符在两个部分中。因此,代码无法满足要求。

可能有不同的方法来解决此问题。

<强>解决方案:

一个不错的(我的首选)解决方案是使用来自OpenXml Powertools的标记简化来规范化xml,这将标准化开放的xml标记以连接段落中的文本以简化编程工作。

示例代码:

using (WordprocessingDocument doc =
            WordprocessingDocument.Open("Test.docx", true))
 {
      SimplifyMarkupSettings settings = new SimplifyMarkupSettings
      {
             NormalizeXml = true, // Merges Run's in a paragraph with similar formatting

       };
        MarkupSimplifier.SimplifyMarkup(doc, settings);
  }

有关使用MarkupSimplifier

的详情,请参阅我的回答here

希望这会有所帮助:)