字符串转义为XML-Attribute

Sim*_*aus 9 c# xml stringbuilder xmlwriter escaping

我看了一下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;
}
Run Code Online (Sandbox Code Playgroud)

这是行不通的.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();
}
Run Code Online (Sandbox Code Playgroud)

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

EDIT2:

SecurityElement.Escape(unescaped);
Run Code Online (Sandbox Code Playgroud)

也不起作用.

Edit3(最后):

使用Lars的所有非常有用的注释,我的最终实现如下所示:

注意:.Replace("\r", "&#xD;").Replace("\n", "&#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;");
    }
Run Code Online (Sandbox Code Playgroud)

事实证明这是有效的XML,并且将由任何符合标准的XMl-parser解析:

<response message="Thank you,
LarsH!" />
Run Code Online (Sandbox Code Playgroud)

Lar*_*rsH 8

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

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

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

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

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

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

SecurityElement.Escape(unescaped).Replace("\r", "&#xD;").Replace("\n", "&#xA;");
Run Code Online (Sandbox Code Playgroud)

要么

return node.InnerXml.Replace("\r", "&#xD;").Replace("\n", "&#xA;");
Run Code Online (Sandbox Code Playgroud)

  • @Simon,仅供参考,该规范(http://www.xml.com/axml/target.html#NT-AttValue)说,你不能在属性值中使用的唯一字符是`<`,报价(以实物为准是用作属性值分隔符)和`&`(除非后者用于实体引用).毫无疑问,这就是为什么SecurityElement.Escape()和XmlAttribute不会转义\n和\ r \n. (2认同)