Лучший способ кодирования текстовых данных для XML



Я искал общий метод в .Net для кодирования строки для использования в Xml-элементе или атрибуте и был удивлен, когда я не сразу нашел его. Итак, прежде чем я пойду слишком далеко, могу ли я просто пропустить встроенную функцию?



предположим на мгновение, что он действительно не существует, я собираю свой собственный универсальный EncodeForXml(string data) метод, и я думаю о лучшем способе сделать это.



данные, которые я использую, что побудило все это могло бы содержат плохие символы, такие как&,


я использовал регулярное выражение в прошлом, чтобы просто поймать плохие амперсанды, и я думаю использовать его, чтобы поймать их в этом случае, а также на первом шаге, а затем сделать простая замена для других персонажей.



Итак, может ли это быть оптимизировано дальше, не делая его слишком сложным, и есть ли что-то, что мне не хватает? :



Function EncodeForXml(ByVal data As String) As String
Static badAmpersand As new Regex("&(?![a-zA-Z]{2,6};|#[0-9]{2,4};)")

data = badAmpersand.Replace(data, "&")

return data.Replace("<", "&lt;").Replace("""", "&quot;").Replace(">", "gt;")
End Function


извините за всех вас C# - только люди - мне все равно, какой язык я использую, но я хотел сделать регулярное выражение статическим, и вы не можете сделать это в C# без объявления его вне метода, так что это будет VB.Net



наконец, мы все еще на .Net 2.0, где я работаю, но если кто-то может возьмите конечный продукт и превратите его в метод расширения для класса string, это тоже было бы довольно круто.



обновление первые несколько ответов показывают, что .Net действительно имеет встроенные способы сделать это. Но теперь, когда я начал, я вроде как хочу закончить свой метод EncodeForXml() просто для удовольствия, поэтому я все еще ищу идеи для улучшения. Примечательно: более полный список символов, которые должны быть закодированы как сущности (возможно, сохраненные в a список / карта), и что-то, что получает лучшую производительность, чем делать .Замените () на неизменяемые строки в последовательном режиме.

628   13  

13 ответов:

в зависимости от того, сколько вы знаете о вводе, вам, возможно, придется принять во внимание, что не все символы Юникода являются допустимыми символами XML.

и сервер.HtmlEncode и

SecurityElement.Побег

документирована здесь

в прошлом я использовал HttpUtility.Htmlencode для кодирования текста в XML. Он выполняет ту же задачу, на самом деле. Я еще не сталкивался с какими-либо проблемами с ним, но это не значит, что я не буду в будущем. Как следует из названия, он был сделан для HTML, а не XML.

Вы, наверное, уже читали это, но вот статья о кодировании и декодировании xml.

EDIT: конечно, если вы используете xmlwriter или один из новых классов XElement, эта кодировка делается для вас. Фактически, вы можете просто взять текст, поместить его в новый экземпляр XElement, а затем вернуть строку (.tostring) версия элемента. Я слышал, что SecurityElement.Побег будет выполнять ту же задачу, что и ваш метод утилиты, но не читал много об этом или использовал его.

EDIT2: не обращайте внимания на мой комментарий о XElement, так как вы все еще на 2.0

Microsoft библиотека AntiXss Класс AntiXssEncoder в системы.Сеть.dll имеет методы для этого:

AntiXss.XmlEncode(string s)
AntiXss.XmlAttributeEncode(string s)

Он также имеет HTML:

AntiXss.HtmlEncode(string s)
AntiXss.HtmlAttributeEncode(string s)

в .net 3.5 с+

new XText("I <want> to & encode this for XML").ToString();

дает вам:

I &lt;want&gt; to &amp; encode this for XML

оказывается, что этот метод не кодирует некоторые вещи, которые он должен (например, кавычки).

SecurityElement.Escape ( ответ workmad3) кажется, чтобы сделать лучшую работу с этим, и он включен в более ранних версиях. net.

Если вы не возражаете против стороннего кода и хотите, чтобы никакие незаконные символы не попадали в ваш XML, я бы рекомендовал ответ Михаила Кропата.

XmlTextWriter.WriteString() не убежать.

Если это ASP.NET приложение, почему бы не использовать сервер.HtmlEncode ()?

Это может быть случай, когда вы могли бы извлечь выгоду из использования метода WriteCData.

public override void WriteCData(string text)
    Member of System.Xml.XmlTextWriter

Summary:
Writes out a <![CDATA[...]]> block containing the specified text.

Parameters:
text: Text to place inside the CDATA block.

простой пример будет выглядеть следующим образом:

writer.WriteStartElement("name");
writer.WriteCData("<unsafe characters>");
writer.WriteFullEndElement();

результат выглядит так:

<name><![CDATA[<unsafe characters>]]></name>

при чтении значений узла XMLReader автоматически удаляет часть CData внутреннего текста, поэтому вам не нужно беспокоиться об этом. Единственная загвоздка заключается в том, что вы должны хранить данные в виде значения innerText для узла XML. Другими словами, вы не можете вставить содержимое в содержимое CDATA-значением атрибута.

гениально! Это все, что я могу сказать.

вот вариант VB обновленного кода (не в классе, а только в функции), который будет очищать, а также дезинфицировать xml

Function cXML(ByVal _buf As String) As String
    Dim textOut As New StringBuilder
    Dim c As Char
    If _buf.Trim Is Nothing OrElse _buf = String.Empty Then Return String.Empty
    For i As Integer = 0 To _buf.Length - 1
        c = _buf(i)
        If Entities.ContainsKey(c) Then
            textOut.Append(Entities.Item(c))
        ElseIf (AscW(c) = &H9 OrElse AscW(c) = &HA OrElse AscW(c) = &HD) OrElse ((AscW(c) >= &H20) AndAlso (AscW(c) <= &HD7FF)) _
            OrElse ((AscW(c) >= &HE000) AndAlso (AscW(c) <= &HFFFD)) OrElse ((AscW(c) >= &H10000) AndAlso (AscW(c) <= &H10FFFF)) Then
            textOut.Append(c)
        End If
    Next
    Return textOut.ToString

End Function

Shared ReadOnly Entities As New Dictionary(Of Char, String)() From {{""""c, "&quot;"}, {"&"c, "&amp;"}, {"'"c, "&apos;"}, {"<"c, "&lt;"}, {">"c, "&gt;"}}

вы можете использовать встроенный класс XAttribute, который обрабатывает кодировку автоматически:

using System.Xml.Linq;

XDocument doc = new XDocument();

List<XAttribute> attributes = new List<XAttribute>();
attributes.Add(new XAttribute("key1", "val1&val11"));
attributes.Add(new XAttribute("key2", "val2"));

XElement elem = new XElement("test", attributes.ToArray());

doc.Add(elem);

string xmlStr = doc.ToString();

вот однострочное решение с использованием XElements. Я использую его в очень маленьком инструменте. Мне это не нужно во второй раз, так что я держу его таким образом. (Его грязный дуг)

StrVal = (<x a=<%= StrVal %>>END</x>).ToString().Replace("<x a=""", "").Replace(">END</x>", "")

О, и он работает только в VB, а не в C#

Если вы серьезно относитесь к обращению все недопустимых символов (а не только несколько "html"), и у вас есть доступ к System.Xml, вот самый простой способ сделать правильное XML-кодирование значение:

string theTextToEscape = "Something \x1d else \x1D <script>alert('123');</script>";
var x = new XmlDocument();
x.LoadXml("<r/>"); // simple, empty root element
x.DocumentElement.InnerText = theTextToEscape; // put in raw string
string escapedText = x.DocumentElement.InnerXml; // Returns:  Something &#x1D; else &#x1D; &lt;script&gt;alert('123');&lt;/script&gt;

// Repeat the last 2 lines to escape additional strings.

важно знать, что XmlConvert.EncodeName() не подходит, потому что это для имен сущностей/тегов, а не значений. Использование этого было бы похоже на URL-кодирование, когда вам нужно было кодировать Html.

Comments

    Ничего не найдено.