【问题标题】:parsing XML with ampersand用 & 符号解析 XML
【发布时间】:2010-12-01 05:22:00
【问题描述】:

我有一个包含 XML 的字符串,我只想将它解析为 Xelement,但它有一个 & 符号。我在用 HtmlDecode 解析它时仍然遇到问题。有什么建议?

string test = " <MyXML><SubXML><XmlEntry Element="test" value="wow&" /></SubXML></MyXML>"; 

XElement.Parse(HttpUtility.HtmlDecode(test));

我还添加了这些方法来替换这些字符,但我仍然收到 XMLException。

string encodedXml = test.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;").Replace("'", "&apos;");
XElement myXML = XElement.Parse(encodedXml);

t 或者甚至用这个尝试过:

string newContent=  SecurityElement.Escape(test);
XElement myXML = XElement.Parse(newContent);

【问题讨论】:

    标签: c# xml xelement


    【解决方案1】:

    理想情况下,在您的代码使用它之前,XML 会被正确转义。如果这超出了您的控制范围,您可以编写一个正则表达式。除非您绝对确定值不包含其他转义项,否则不要使用 String.Replace 方法。

    例如,"wow&amp;amp;".Replace("&amp;", "&amp;amp;") 会导致 wow&amp;amp;amp;,这显然是不可取的。

    Regex.Replace 可以为您提供更多控制以避免这种情况,并且可以编写为仅匹配不属于其他字符的“&”符号,例如&amp;lt;,例如:

    string result = Regex.Replace(test, "&(?!(amp|apos|quot|lt|gt);)", "&amp;");
    

    上述方法有效,但不可否认,它不包括以 & 符号开头的各种其他字符,例如 &amp;nbsp;,并且列表可能会增加。

    更灵活的方法是解码 value 属性的内容,然后重新编码。如果您有value="&amp;wow&amp;amp;",则解码过程将返回"&amp;wow&amp;",然后重新编码将返回"&amp;amp;wow&amp;amp;",这是可取的。要做到这一点,你可以使用这个:

    string result = Regex.Replace(test, @"value=\""(.*?)\""", m => "value=\"" +
        HttpUtility.HtmlEncode(HttpUtility.HtmlDecode(m.Groups[1].Value)) +
        "\"");
    var doc = XElement.Parse(result);
    

    请记住,上面的正则表达式只针对 value 属性的内容。如果 XML 结构中的其他区域存在相同的问题,则可以对其进行调整以匹配它们并以类似的方式替换它们的内容。


    编辑: 更新的解决方案应该处理标签之间的内容以及双引号之间的任何内容。请务必彻底测试。尝试使用正则表达式操作 XML/HTML 标记是不利的,因为它容易出错且过于复杂。您的情况有些特殊,因为您需要先对其进行消毒才能使用它。
    string pattern = "(?<start>>)(?<content>.+?(?<!>))(?<end><)|(?<start>\")(?<content>.+?)(?<end>\")";
    string result = Regex.Replace(test, pattern, m =>
                m.Groups["start"].Value +
                HttpUtility.HtmlEncode(HttpUtility.HtmlDecode(m.Groups["content"].Value)) +
                m.Groups["end"].Value);
    var doc = XElement.Parse(result);
    

    【讨论】:

    • 您的解决方案是完美的,但是否也可以将正则表达式用于 XML 值。因为正如你所说,这只适用于属性。例如在这种情况下:this & that
    • @paradisonoir:是的,看我的编辑。正如我所说,确保彻底测试它。
    • 这种方法似乎假设“一次一个元素”。那是对的吗?我有一个与 OP 类似的问题,我试图在加载 XML 文件之前对其进行清理,但是我的行有多个节点,结果不是预期的。有没有办法将此模式应用于具有多个节点 hello&world 的行?
    • @Ben:使用上面使用命名组的 sn-p 尝试此模式:string pattern = "(?&lt;=&gt;)(?&lt;content&gt;[^&gt;]+)(?=&lt;)|(?&lt;start&gt;\")(?&lt;content&gt;.+?)(?&lt;end&gt;\")";
    • 与号后面也可以跟数字代码。 ’也可以用 ' 表示或 '或 '使用:字符串结果 = Regex.Replace(test, @"&(?!(quot|amp|apos|lt|gt|#x?\d{2,3});)", "&");
    【解决方案2】:

    您的字符串不包含有效的 XML,这就是问题所在。您需要将字符串更改为:

    <MyXML><SubXML><XmlEntry Element="test" value="wow&amp;" /></SubXML></MyXML>"
    

    【讨论】:

    • 谢谢,但我只是想知道怎么做?最好的方法是什么?
    • 视情况而定。如果你总是从一个字符串对象解析,你可以做一个简单的 test=test.Replace("&","&");
    • 好吧,那替换了字符,但是当我想解析时,我仍然有一些问题。我添加了我的新方法。
    • 那是因为你换的太多了。您应该只需要更换安培和。如果替换大于和小于符号,则根本没有任何标签。
    【解决方案3】:

    HtmlEncode 无法解决问题,它可能会创建更多的 & 符号(例如,' 可能会变成 ",这是一个 Xml 实体引用,如下所示:

    &amp;   & 
    &apos;  ' 
    &quot;  " 
    &lt;    < 
    &gt;    > 
    

    但是你可能会得到像 &nbsp 这样的东西,它在 html 中很好,但在 Xml 中不行。因此,就像其他人所说的那样,首先通过确保 不属于您的 XML 实际标记的任何字符来更正 xml(也就是说,您的 xml 中的任何内容作为变量或文本),并且出现在实体引用列表中的内容被翻译成它们对应的实体(所以

    【讨论】:

    • 但是你建议怎么做呢?
    • 好吧,我建议您在创建 Xml 文件之前进行,假设您当然是创建 Xml 文件的人。如果您无法控制 xml 文件的创建(因为它是从某个地方下载的),我建议您联系负责人并让他在将 xml 发送给您之前对其进行清理。
    • 如果您可以控制 xml 文件的创建,请使用正则表达式(抱歉,我很讨厌正则表达式无法给出示例)或者只是像这样的链式替换:string.Replace(" &", "&").Replace("'", """).etc.etc.
    【解决方案4】:

    与号使 XML 无效。这无法通过样式表修复,因此您需要使用其他工具或 VB/C#/PHP/Delphi/Lisp/Etc 中的代码编写代码。删除它或将其翻译成 &.

    【讨论】:

      【解决方案5】:

      如果您的字符串不是有效的 XML,它将不会被解析。如果它本身包含一个 & 符号,则它不是有效的 XML。与 HTML 不同,XML 非常严格。

      【讨论】:

        【解决方案6】:

        您应该“编码”而不是解码。但是调用 HttpUtility.HtmlEncode 对您没有帮助,因为它还会对您的“”符号进行编码,并且您的字符串将不再是 XML。

        我认为对于这种情况,最好的解决方案是将 '&' 替换为 '& amp;' (没有空格)

        【讨论】:

        • 但是你建议怎么做呢?
        • test.Replace("&", "&") 会做我猜的伎俩。您不需要 Replace("
        【解决方案7】:

        也许考虑编写自己的 XMLDocumentScanner。这就是 NekoHTML 正在做的事情,以便能够忽略不用作实体引用的 & 符号。

        【讨论】:

          【解决方案8】:

          这是最简单也是最好的方法。适用于所有字符,并允许为任何 Web 服务调用(即 SharePoint ASMX)解析 XML。

          public string XmlEscape(string unescaped)
                  {
                      XmlDocument doc = new XmlDocument();
                      var node = doc.CreateElement("root");
                      node.InnerText = unescaped;
                      return node.InnerXml;
                  }
          

          【讨论】:

            【解决方案9】:

            Filip's 答案在正确的轨道上,但您可以劫持 System.Xml.XmlDocument 类为您执行此操作,而无需全新的实用功能。

            XmlDocument doc = new XmlDocument();
            string xmlEscapedString = (doc.CreateTextNode("Unescaped '&' containing string that would have broken your xml")).OuterXml;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-01-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多