Лучший способ кодировать текстовые данные для XML - PullRequest
67 голосов
/ 01 октября 2008

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

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

Данные, которые я использую, которые запрашивали все это, могли содержать недопустимые символы, такие как &, <, "и т. Д. Иногда они могли также содержать правильно экранированные сущности: & amp ;, & lt; и & quot ;, что означает просто использование раздела CDATA может быть не самой лучшей идеей. В любом случае, это кажется немного хитрым, я бы предпочел получить хорошее строковое значение, которое можно использовать непосредственно в xml. </p>

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

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

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, "&amp;")

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

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

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

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

Ответы [ 13 ]

0 голосов
/ 30 марта 2017

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

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

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

0 голосов
/ 23 апреля 2015

Вы можете использовать встроенный класс 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();
0 голосов
/ 18 ноября 2011

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

Вот вариант 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;"}}
...