Лучший способ кодирования текстовых данных для 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("<", "<").Replace("""", """).Replace(">", "gt;")
End Function
извините за всех вас C# - только люди - мне все равно, какой язык я использую, но я хотел сделать регулярное выражение статическим, и вы не можете сделать это в C# без объявления его вне метода, так что это будет VB.Net
наконец, мы все еще на .Net 2.0, где я работаю, но если кто-то может возьмите конечный продукт и превратите его в метод расширения для класса string, это тоже было бы довольно круто.
обновление первые несколько ответов показывают, что .Net действительно имеет встроенные способы сделать это. Но теперь, когда я начал, я вроде как хочу закончить свой метод EncodeForXml() просто для удовольствия, поэтому я все еще ищу идеи для улучшения. Примечательно: более полный список символов, которые должны быть закодированы как сущности (возможно, сохраненные в a список / карта), и что-то, что получает лучшую производительность, чем делать .Замените () на неизменяемые строки в последовательном режиме.
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 <want> to & encode this for XMLоказывается, что этот метод не кодирует некоторые вещи, которые он должен (например, кавычки).
SecurityElement.Escape( ответ workmad3) кажется, чтобы сделать лучшую работу с этим, и он включен в более ранних версиях. net.Если вы не возражаете против стороннего кода и хотите, чтобы никакие незаконные символы не попадали в ваш XML, я бы рекомендовал ответ Михаила Кропата.
Это может быть случай, когда вы могли бы извлечь выгоду из использования метода 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, """}, {"&"c, "&"}, {"'"c, "'"}, {"<"c, "<"}, {">"c, ">"}}
вы можете использовать встроенный класс 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  else  <script>alert('123');</script> // Repeat the last 2 lines to escape additional strings.важно знать, что
XmlConvert.EncodeName()не подходит, потому что это для имен сущностей/тегов, а не значений. Использование этого было бы похоже на URL-кодирование, когда вам нужно было кодировать Html.
Comments