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

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

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

Данные, которые я использую, вызвали все это, могут содержать плохие символы, такие как &, <, "и т. Д. Он также может иногда содержать правильно экранированные объекты: & amp ;, & lt ;, & quot ;, что означает просто использование Раздел CDATA не может быть лучшей идеей. Это похоже на klunky anyay, я бы скорее получил отличное строковое значение, которое можно использовать непосредственно в xml.

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

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

 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("", "gt;") End Function 

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

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

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

System.XML обрабатывает кодировку для вас, поэтому вам не нужен такой метод.

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

Как Server.HtmlEncode, так и System.Security.SecurityElement.Escape, похоже, игнорируют нелегальные символы XML, а System.XML.XmlWriter.WriteString выдает исключение ArgumentException, когда он встречает незаконные символы (если вы не отключите эту проверку, и в этом случае она игнорирует их). Обзор функций библиотеки доступен здесь .

Редактировать 2011/8/14: видя, что по крайней мере несколько человек проконсультировались с этим ответом за последние пару лет, я решил полностью переписать исходный код, в котором было много проблем, в том числе ужасно неправильное обращение с UTF-16 .

 using System; using System.Collections.Generic; using System.IO; using System.Linq; ///  /// Encodes data so that it can be safely embedded as text in XML documents. ///  public class XmlTextEncoder : TextReader { public static string Encode(string s) { using (var stream = new StringReader(s)) using (var encoder = new XmlTextEncoder(stream)) { return encoder.ReadToEnd(); } } /// The data to be encoded in UTF-16 format. /// It is illegal to encode certain /// characters in XML. If true, silently omit these characters from the /// output; if false, throw an error when encountered. public XmlTextEncoder(TextReader source, bool filterIllegalChars=true) { _source = source; _filterIllegalChars = filterIllegalChars; } readonly Queue _buf = new Queue(); readonly bool _filterIllegalChars; readonly TextReader _source; public override int Peek() { PopulateBuffer(); if (_buf.Count == 0) return -1; return _buf.Peek(); } public override int Read() { PopulateBuffer(); if (_buf.Count == 0) return -1; return _buf.Dequeue(); } void PopulateBuffer() { const int endSentinel = -1; while (_buf.Count == 0 && _source.Peek() != endSentinel) { // Strings in .NET are assumed to be UTF-16 encoded [1]. var c = (char) _source.Read(); if (Entities.ContainsKey(c)) { // Encode all entities defined in the XML spec [2]. foreach (var i in Entities[c]) _buf.Enqueue(i); } else if (!(0x0 <= c && c <= 0x8) && !new[] { 0xB, 0xC }.Contains(c) && !(0xE <= c && c <= 0x1F) && !(0x7F <= c && c <= 0x84) && !(0x86 <= c && c <= 0x9F) && !(0xD800 <= c && c <= 0xDFFF) && !new[] { 0xFFFE, 0xFFFF }.Contains(c)) { // Allow if the Unicode codepoint is legal in XML [3]. _buf.Enqueue(c); } else if (char.IsHighSurrogate(c) && _source.Peek() != endSentinel && char.IsLowSurrogate((char) _source.Peek())) { // Allow well-formed surrogate pairs [1]. _buf.Enqueue(c); _buf.Enqueue((char) _source.Read()); } else if (!_filterIllegalChars) { // Note that we cannot encode illegal characters as entity // references due to the "Legal Character" constraint of // XML [4]. Nor are they allowed in CDATA sections [5]. throw new ArgumentException( String.Format("Illegal character: '{0:X}'", (int) c)); } } } static readonly Dictionary Entities = new Dictionary { { '"', """ }, { '&', "&"}, { '\'', "'" }, { '<', "<" }, { '>', ">" }, }; // References: // [1] http://en.wikipedia.org/wiki/UTF-16/UCS-2 // [2] http://www.w3.org/TR/xml11/#sec-predefined-ent // [3] http://www.w3.org/TR/xml11/#charsets // [4] http://www.w3.org/TR/xml11/#sec-references // [5] http://www.w3.org/TR/xml11/#sec-cdata-sect } 

Единичные тесты и полный код можно найти здесь .

SecurityElement.Escape

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

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

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

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

EDIT2: проигнорируйте мой комментарий о XElement, так как вы все еще на 2.0

В библиотеке AntiXss от Microsoft AntiXssEncoder Class в System.Web.dll есть методы для этого:

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

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

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

В .net 3.5+

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

Дает тебе:

I <want> to & encode this for XML

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

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

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

XmlTextWriter.WriteString() выполняет экранирование.

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

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

 public override void WriteCData(string text) Member of System.Xml.XmlTextWriter Summary: Writes out a  block containing the specified text. Parameters: text: Text to place inside the CDATA block. 

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

 writer.WriteStartElement("name"); writer.WriteCData(""); writer.WriteFullEndElement(); 

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

 ]]> 

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

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

Вот вариант VB обновленного кода (не в classе, просто функция), который будет очищать, а также дезинфицировать 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, ">"}} 

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

 using System.Xml.Linq; XDocument doc = new XDocument(); List attributes = new List(); 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 = (>END).ToString().Replace("END", "") 

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

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

 string theTextToEscape = "Something \x1d else \x1D "; var x = new XmlDocument(); x.LoadXml(""); // 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-encode.

  • Поместите кнопки внизу экрана с помощью LinearLayout?
  • Как я могу разделить два файла XML?
  • Итерирование атрибутов элементов с помощью jQuery
  • Извлечение данных из простого XML-файла
  • Изменить существующий контент XML в C #
  • Преобразование набора данных в XML
  • Сериализовать значение nullable int
  • Импорт XML-файлов в PostgreSQL
  • Параметры макета Android XML не работают, как ожидалось
  • Что означает X в ASPX, DOCX, XLSX, PPTX и т. Д.?
  • Как добиться условного импорта ресурсов в контексте Spring XML?
  • Давайте будем гением компьютера.