Frage

Ich suchte nach einer generischen Methode in .NET, um eine Zeichenfolge für die Verwendung in einem XML -Element oder -attribut zu codieren, und war überrascht, als ich nicht sofort einen fand. Bevor ich zu viel weiter gehe, könnte ich nur die integrierte Funktion verpassen?

Angenommen, ich stelle für einen Moment nicht vor EncodeForXml(string data) Methode, und ich denke über den besten Weg nach, dies zu tun.

Die Daten, die ich verwende, die diese ganze Sache veranlasst haben, könnte schlechte Zeichen wie &, <, "usw. enthalten. Es könnte gelegentlich auch die richtig entkommenen Wesenheiten enthalten: &, <und", was bedeutet, nur einen CDATA -Abschnitt zu verwenden, Mai Mai nicht die beste Idee sein. Das scheint irgendwie klunky an jeden zu sein; Ich würde viel lieber einen schönen String -Wert haben, der direkt im XML verwendet werden kann.

Ich habe in der Vergangenheit einen regelmäßigen Ausdruck verwendet, um nur schlechte Verstärker zu fangen, und ich denke darüber nach, ihn in diesem Fall sowie im ersten Schritt zu fangen und dann einen einfachen Ersatz für andere Charaktere zu machen.

Könnte dies also weiter optimiert werden, ohne es zu komplex zu machen, und fehlt mir etwas? :

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

Entschuldigung für alle Leute-nur Leute-es ist mir egal, welche Sprache ich verwende, aber ich wollte den Regex statisch machen und das kann man in C# nicht tun, ohne sie außerhalb der Methode zu erklären, also wird dies VB sein .Netz

Schließlich sind wir immer noch auf .NET 2.0, wo ich arbeite, aber wenn jemand das Endprodukt in eine Erweiterungsmethode für die String -Klasse verwandeln könnte, wäre das auch ziemlich cool.

Aktualisieren Die ersten Antworten deuten darauf hin, dass .NET tatsächlich integrierte Möglichkeiten hat, dies zu tun. Aber jetzt, wo ich angefangen habe, möchte ich meine methode codeforxml () nur zum Spaß beenden, also suche ich immer noch nach Verbesserungsideen. Bemerkenswerterweise: Eine vollständigere Liste von Zeichen, die als Entitäten (möglicherweise in einer Liste/Karte gespeichert) codiert werden sollten, und etwas, das eine bessere Leistung erzielt, als eine .replace () auf unveränderlichen Zeichenfolgen in der Serie zu machen.

War es hilfreich?

Lösung

System.xml behandelt die Codierung für Sie, sodass Sie keine solche Methode benötigen.

Andere Tipps

Je nachdem, wie viel Sie über die Eingabe wissen, müssen Sie dies möglicherweise berücksichtigen Nicht alle Unicode -Zeichen sind gültige XML -Zeichen.

Beide Server.htmlencode und System.security.securityElement.escape scheinen illegale XML -Charaktere zu ignorieren, während System.xml.xmlwriter.Writestring wirft ein ArgumentException Wenn es illegale Zeichen trifft (es sei denn, Sie deaktivieren diese Überprüfung in diesem Fall ignoriert sie). Ein Überblick über Bibliotheksfunktionen ist verfügbar hier.

Bearbeiten 2011/8/14: Als ich sah, dass mindestens ein paar Leute diese Antwort in den letzten Jahren konsultiert haben, beschloss ich, den ursprünglichen Code komplett umzuschreiben, der zahlreiche Probleme hatte, einschließlich schrecklich misshandelte UTF-16.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

/// <summary>
/// Encodes data so that it can be safely embedded as text in XML documents.
/// </summary>
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();
        }
    }

    /// <param name="source">The data to be encoded in UTF-16 format.</param>
    /// <param name="filterIllegalChars">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.</param>
    public XmlTextEncoder(TextReader source, bool filterIllegalChars=true) {
        _source = source;
        _filterIllegalChars = filterIllegalChars;
    }

    readonly Queue<char> _buf = new Queue<char>();
    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<char,string> Entities =
        new Dictionary<char,string> {
            { '"', "&quot;" }, { '&', "&amp;"}, { '\'', "&apos;" },
            { '<', "&lt;" }, { '>', "&gt;" },
        };

    // 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
}

Unit -Tests und vollständige Code können gefunden werden hier.

Sicherheitselement.eskape

dokumentiert hier

In der Vergangenheit habe ich httputility.htmlencode verwendet, um Text für XML zu codieren. Es führt wirklich die gleiche Aufgabe aus. Ich bin noch nicht auf Probleme damit gestoßen, aber das heißt nicht, dass ich in Zukunft nicht werde. Wie der Name schon sagt, wurde es für HTML, nicht XML, gemacht.

Sie haben es wahrscheinlich schon gelesen, aber Hier ist ein Artikel auf XML -Codierung und Decodierung.

Bearbeiten: Wenn Sie natürlich einen XMLWriter oder eine der neuen Xelement -Klassen verwenden, ist diese Codierung für Sie durchgeführt. Tatsächlich können Sie den Text einfach nehmen, ihn in eine neue Xelement -Instanz platzieren und dann die String (.toString) -Version des Elements zurückgeben. Das habe ich gehört Sicherheitselement.eskape Erfüllt dieselbe Aufgabe auch wie Ihre Dienstprogrammmethode, hat aber nicht viel darüber gelesen oder verwendet.

Edit2: Ignorieren Sie meinen Kommentar zu Xelement, da Sie noch auf 2.0 sind

Microsoft's Antixss Library ANTIXSSENCODER -Klasse In System.web.dll hat Methoden dafür:

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

Es hat auch HTML:

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

In .net 3.5+

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

Gibt Ihnen:

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

Es stellt sich heraus, dass diese Methode einige Dinge nicht codiert, die sie sollte (wie Zitate).

SecurityElement.Escape (Antwort von Workmad3) scheint damit einen besseren Job zu machen und es ist in früheren Versionen von .NET enthalten.

Wenn Sie nichts ausmachen, den Code von Drittanbietern und sicherstellen möchten, dass keine illegalen Zeichen in Ihr XML eingehen, würde ich empfehlen, Michael Kropats Antwort.

XmlTextWriter.WriteString() Flucht.

Wenn dies eine ASP.NET -App ist, warum nicht server.htmlencode () verwenden?

Dies kann der Fall sein, in dem Sie von der Verwendung der WriteCData -Methode profitieren können.

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.

Ein einfaches Beispiel würde wie Folgendes aussehen:

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

Das Ergebnis sieht aus:

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

Beim Lesen des Knotenwerts streift der XMLReader automatisch den CDATA -Teil des InnerText aus, sodass Sie sich keine Sorgen machen müssen. Der einzige Haken ist, dass Sie die Daten als InnerText -Wert für einen XML -Knoten speichern müssen. Mit anderen Worten, Sie können den CDATA -Inhalt nicht in einen Attributwert einfügen.

Brillant! Das ist alles was ich sagen kann.

Hier ist eine VB

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

Sie können die integrierte Klasse verwenden Xattribute, was die Codierung automatisch behandelt:

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();

Hier ist eine einzelne Leitungslösung mit den Xelements. Ich benutze es in einem sehr kleinen Werkzeug. Ich brauche es kein zweites Mal, also halte ich es so. (Sein Dirdy Doug)

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

Oh und es funktioniert nur in VB nicht in C#

Wenn Sie es ernst meinen, umzugehen alle der ungültigen Zeichen (nicht nur die wenigen "HTML"), und Sie haben Zugriff auf System.Xml, Hier ist der einfachste Weg, um eine ordnungsgemäße XML -Codierung von zu machen Messwert:

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.

Es ist wichtig, das zu wissen XmlConvert.EncodeName() ist nicht angemessen, da dies für Entitäts-/Tag -Namen und keine Werte gilt. Das Verwenden wäre wie URL-Kodierung, wenn Sie HTML-Codes benötigen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top