экранирование строки в XML-атрибут - PullRequest
9 голосов
/ 16 декабря 2010

Я посмотрел на выход строки в XML и нашел его очень полезным.

Я хотел бы сделать аналогичную вещь: экранировать строку для использования в XML-атрибуте.

Строка может содержать \ r \ n. Класс XmlWriter создает что-то вроде \ r \ n -> & # xD; & # xA;

Решение, которое я сейчас использую, включает в себя XmlWriter и StringBuilder и довольно уродливо.

Есть намеки?

Edit1:
Извините, что разочаровал 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&#xD;&#xA;Bar"

Edit2:

SecurityElement.Escape(unescaped);

тоже не работает.

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;");
    }

Как выясняется, это допустимый XML и будет проанализирован любым стандартным XMl-анализатором:

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

Ответы [ 2 ]

7 голосов
/ 16 декабря 2010

Изменение решения, на которое вы ссылались, как насчет

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;");
0 голосов
/ 16 декабря 2010

если это может быть полезно, на нескольких языках каждый использует createCDATASection, чтобы избежать всех специальных символов XML.

Он добавляет что-то вроде этого:

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