【问题标题】:string escape into XML-Attribute字符串转义到 XML-Attribute
【发布时间】:2011-05-26 17:38:52
【问题描述】:

我查看了string escape into XML,发现它非常有用。

我想做类似的事情:转义要在 XML-Attribute 中使用的字符串。

字符串可能包含\r\n。 XmlWriter 类产生类似 \r\n ->

我目前使用的解决方案包括 XmlWriter 和 StringBuilder,而且相当难看。

有什么提示吗?

编辑1:
很抱歉让 LarsH 失望,买我的第一个方法是

public static string XmlEscapeAttribute(string unescaped)
{
    XmlDocument doc = new XmlDocument();
    XmlAttribute attr= doc.CreateAttribute("attr");
    attr.InnerText = unescaped;
    return attr.InnerXml;
}

它不起作用。 XmlEscapeAttribute("Foo\r\nBar") 将导致 "Foo\r\nBar"

我使用 .NET Reflector 来了解 XmlTextWriter 如何转义属性。它使用内部的 XmlTextEncoder 类...

我目前使用的方法是这样的:

public static string XmlEscapeAttribute(string unescaped)
{
    if (String.IsNullOrEmpty(unescaped)) return unescaped;

    XmlWriterSettings settings = new XmlWriterSettings();
    settings.OmitXmlDeclaration = true;
    StringBuilder sb = new StringBuilder();
    XmlWriter writer = XmlWriter.Create(sb, settings);

    writer.WriteStartElement("a");
    writer.WriteAttributeString("a", unescaped);
    writer.WriteEndElement();
    writer.Flush();
    sb.Length -= "\" />".Length;
    sb.Remove(0, "<a a=\"".Length);

    return sb.ToString();
}

它很丑而且可能很慢,但它确实有效:XmlEscapeAttribute("Foo\r\nBar") 将导致 "Foo&amp;#xD;&amp;#xA;Bar"

编辑2:

SecurityElement.Escape(unescaped);

也不行。

Edit3(最终版):

使用来自 Lars 的所有非常有用的 cmets,我的最终实现如下所示:

注意.Replace("\r", "&amp;#xD;").Replace("\n", "&amp;#xA;"); 不是有效 XMl 所必需的。这只是一种美容措施!

    public static string XmlEscapeAttribute(string unescaped)
    {

        XmlDocument doc = new XmlDocument();
        XmlAttribute attr= doc.CreateAttribute("attr");
        attr.InnerText = unescaped;
        // The Replace is *not* required!
        return attr.InnerXml.Replace("\r", "&#xD;").Replace("\n", "&#xA;");
    }

事实证明这是有效的 XML,将被任何符合标准的 XMl 解析器解析:

<response message="Thank you,
LarsH!" />

【问题讨论】:

  • 您能否修改上面链接到的答案中的技术,以便它创建一个属性节点,将字符串填充到节点的 innerText 中,并提取其 innerXML?如果您只是将 CreateElement() 更改为 CreateAttribute() 会发生什么?
  • 你也应该确保转义双引号。

标签: c# xml escaping stringbuilder xmlwriter


【解决方案1】:

修改你引用的方案,怎么样

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

我所做的只是将 CreateElement() 更改为 CreateAttribute()。 属性节点类型确实具有 InnerText 和 InnerXml 属性。

我没有测试它的环境,但我很想知道它是否有效。

更新:或者更简单地说,使用SecurityElement.Escape(),如您链接到的问题的另一个答案中所建议的那样。这将转义引号,因此适合用于属性文本。

更新 2:请注意回车和换行不需要在属性值中转义,以使 XML 格式正确。如果您希望它们因其他原因被转义,您可以使用 String.replace() 来实现,例如

SecurityElement.Escape(unescaped).Replace("\r", "&#xD;").Replace("\n", "&#xA;");

return node.InnerXml.Replace("\r", "&#xD;").Replace("\n", "&#xA;");

【讨论】:

  • @Simon,你会把你的车开到修理工那里,然后说它“不工作”吗?如何具体说明实际发生的事情?以及它与您的预期有何不同。否则,您让我们猜测问题所在。
  • "
  • @Simon,为什么你说你不能在属性字符串中使用 \r\n ?请引用参考。当我在 Oxygen XML 编辑器中输入&lt;a foo="Foo\nbar" /&gt;(对 \n 使用换行符)并要求它检查格式良好时,它说文档格式正确。
  • @Simon,仅供参考,规范 (xml.com/axml/target.html#NT-AttValue) 说您不能在属性值中使用的唯一字符是 &lt;,引号(无论哪种类型用作属性值分隔符) , 和&amp;(除非后者用于实体引用)。毫无疑问,这就是为什么 SecurityElement.Escape() 和 XmlAttribute 没有转义 \n 和 \r。
  • @LarsH:我很抱歉给你带来的所有麻烦。当然,你是对的:&lt;a foo="Foo\nbar" /&gt; 是有效的并且可以很好地解析。我只是假设它不是有效的 XML,因为它看起来不适合我,并且 XmlWriter 类转义了 \r 和 \n。感谢您的耐心和良好的回答!
【解决方案2】:
public static string XmlEscapeAttribute(string unescaped)
{
    if (string.IsNullOrEmpty(unescaped))
        return unescaped;

    var attributeString = new XAttribute("n", unescaped).ToString();

    // Extract the string from the text like: n="text".
    return attributeString.Substring(3, attributeString.Length - 4);
}

此解决方案类似于@Mathias E. 提出的解决方案,但它使用 LINQ to XML 而不是 XmlDocument,因此应该更快。

SecurityElement.Escape() 解决方案有几个问题。首先,它不会对新行进行编码,因此必须作为附加步骤来完成。此外,它将撇号编码为&amp;apos;,这在XML spec 的属性值中是不正确的。

我的解决方案的灵感来自this post

【讨论】:

  • 你为什么说“&amp;apos; 根据 XML 规范的属性值不正确”?您链接到的AttValue 产品表明它可以包含实体引用,其格式为'&amp;' Name ';'。事实上,xml.com/axml/target.html#syntax 明确表示“为了允许属性值同时包含单引号和双引号,撇号或单引号字符 (') 可以表示为 "&'"...'
  • 也不清楚“SecurityElement.Escape()... 不编码新行”是什么意思。它确实将它们编码为文字换行符。也许您的意思是它不使用字符引用对它们进行编码?如果在某些情况下这是一个问题,那么澄清它何时/为什么是一个问题会很有帮助,因为这不是一般的问题。
【解决方案3】:

如果有任何帮助,在几种语言中,使用 createCDATASection 来避免所有 XML 特殊字符。

它添加了这样的东西:

<tag><![CDATA[ <somecontent/> ]]></tag>

【讨论】:

  • @Matthias,OP 询问如何转义要在 属性中使用的字符串。你能把 CDATA 部分放在属性值中吗?
  • 我应该在回复之前阅读问题... CDATA 不能用于属性值。
猜你喜欢
  • 2010-11-11
  • 2014-04-10
  • 2012-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
相关资源
最近更新 更多