String-Escape in XML

90

Gibt es eine C # -Funktion, mit der eine Zeichenfolge maskiert und nicht maskiert werden kann, um den Inhalt eines XML-Elements auszufüllen?

Ich verwende VSTS 2008 + C # + .Net 3.0.

EDIT 1: Ich bin einfach und kurz XML - Datei verketten und ich verwende die Serialisierung nicht, so dass ich explizit muß XML - Zeichen mit der Hand entkommen, zum Beispiel, ich brauche zu setzen a<bin <foo></foo>, so dass ich String entkommen muss a<bund es in dem Elemente foo setzen.

George2
quelle
15
Am kürzesten kann ich mir new XText(unescaped).ToString()
vorstellen
3
Für alle anderen, die darüber stolpern, ist dies die beste Antwort: stackoverflow.com/a/5304827/1224069
Philip Pittle

Antworten:

74
public static string XmlEscape(string unescaped)
{
    XmlDocument doc = new XmlDocument();
    XmlNode node = doc.CreateElement("root");
    node.InnerText = unescaped;
    return node.InnerXml;
}

public static string XmlUnescape(string escaped)
{
    XmlDocument doc = new XmlDocument();
    XmlNode node = doc.CreateElement("root");
    node.InnerXml = escaped;
    return node.InnerText;
}
Darin Dimitrov
quelle
5
Sie müssen das Element nicht einmal an das Dokument anhängen. Ich würde jedoch immer noch sagen, dass es am besten ist, dies überhaupt nicht zu versuchen - es klingt so, als würde George Arbeit für sich selbst machen, indem er Dinge von Hand macht ...
Jon Skeet
15
Ich mag diese Antwort wirklich nicht, weil sie zu schwer ist. XmlDocument wird XmlReader / XmlWriter verwenden, um die eigentliche Arbeit zu erledigen. Warum also nicht auf den Punkt kommen und dieses schwere DOM vermeiden?
Steven Sudit
7
@Will, das OP hat nach einer Funktion gefragt, die einem Text entgeht, der in ein XML- Element und nicht in ein Attribut eingefügt werden kann. Meine Funktion entgeht keinen einfachen oder doppelten Anführungszeichen, da sie in XML-Elemente eingefügt werden können.
Darin Dimitrov
5
@ Darin guter Punkt, und einer, der betont werden sollte. Ich bin mit dem Ergebnis dieses Gesprächs zufrieden und ziehe meine Reservierungen zurück. Guten Tag Herr.
1
Ich frage mich, ob HttpUtility.HtmlEncodevon System.Websicher verwendet werden könnte?
Pooven
126

SecurityElement.Escape (Zeichenfolge s)

Dana Holt
quelle
8
Diese Antwort entgeht im Gegensatz zur ausgewählten Antwort Anführungszeichen.
1
Diese Antwort scheint nicht mit ungültigen Zeichen wie
Haacked
16
Und wie entkommst du?
Gondy
2
Diese Antwort ist unvollständig. Es beantwortet nur die Hälfte der Frage.
Brian Webster
1
Stimmen Sie den obigen Kommentaren zu - unvollständig und nicht 100% genau.
G. Stoynev
38

BEARBEITEN: Sie sagen "Ich verkette einfache und kurze XML-Dateien und verwende keine Serialisierung, daher muss ich XML-Zeichen explizit von Hand maskieren".

Ich würde Ihnen dringend raten, dies nicht von Hand zu tun. Verwenden Sie die XML-APIs, um alles für Sie zu erledigen - lesen Sie die Originaldateien ein und führen Sie die beiden Dateien zu einem einzigen Dokument zusammen, wie Sie möchten (wahrscheinlich möchten Sie es verwenden)XmlDocument.ImportNode ), und schreiben Sie es dann erneut aus. Sie möchten keine eigenen XML-Parser / Formatierer schreiben. Serialisierung ist hier etwas irrelevant.

Wenn Sie uns ein kurzes, aber vollständiges Beispiel dafür geben können, was Sie genau tun möchten, können wir Ihnen wahrscheinlich dabei helfen, sich keine Sorgen über die Flucht machen zu müssen.


Ursprüngliche Antwort

Es ist nicht ganz klar, was Sie meinen, aber normalerweise erledigen XML-APIs dies für Sie. Sie legen den Text in einem Knoten fest und er entgeht automatisch allem, was er benötigt. Beispielsweise:

Beispiel für LINQ to XML:

using System;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        XElement element = new XElement("tag",
                                        "Brackets & stuff <>");

        Console.WriteLine(element);
    }
}

DOM-Beispiel:

using System;
using System.Xml;

class Test
{
    static void Main()
    {
        XmlDocument doc = new XmlDocument();
        XmlElement element = doc.CreateElement("tag");
        element.InnerText = "Brackets & stuff <>";
        Console.WriteLine(element.OuterXml);
    }
}

Ausgabe aus beiden Beispielen:

<tag>Brackets &amp; stuff &lt;&gt;</tag>

Dies setzt natürlich voraus, dass XML entkommen soll. Wenn nicht, posten Sie bitte weitere Details.

Jon Skeet
quelle
Danke Jon, ich habe mehr Details in meinen ursprünglichen Beitrag nach EDIT 1 aufgenommen. Schätzen Sie, wenn Sie mir einige Kommentare und Ratschläge geben könnten. :-)
George2
"Nach dem Entkommen von XML" - meinst du? Könnten Sie bitte mit anderen Worten sprechen? Englisch ist nicht meine Muttersprache. :-)
George2
Hallo Jon, wie kann man vom XML-Format in das normale Zeichenfolgenformat entkommen, dh von der Eingabe "Klammern & amp; Zeug & lt; & gt;" erhalten wir die Ausgabe "Klammern & Zeug <>"?
George2
2
@ George2: Sie fragen das XElement nach seinem Wert oder das XmlElement nach seinem InnerText.
Jon Skeet
25

Vielen Dank an @sehe für die einzeilige Flucht:

var escaped = new System.Xml.Linq.XText(unescaped).ToString();

Ich füge noch die einzeilige Flucht hinzu:

var unescapedAgain = System.Xml.XmlReader.Create(new StringReader("<r>" + escaped + "</r>")).ReadElementString();
Keith Robertson
quelle
XText entgeht keinen Anführungszeichen.
Mert Gülsoy
9

George, es ist einfach. Verwenden Sie immer die XML-APIs, um mit XML umzugehen. Sie erledigen alles für Sie, um zu entkommen und zu entkommen.

Erstellen Sie niemals XML, indem Sie Zeichenfolgen anhängen.

John Saunders
quelle
Worte nach denen man sich richten sollte. Es gibt viele XML-API-Optionen, aber wir sollten uns alle einig sein, dass die manuelle Verkettung von Zeichenfolgen nicht akzeptabel ist.
Steven Sudit
Obwohl ich dem im Allgemeinen zustimme, kann es einige sehr seltene Fälle geben, in denen ein manuelles Entkommen erforderlich sein kann. Zum Beispiel beim Erstellen einer XML-Dokumentation mit Roslyn.
Svick
@svick: Warum nicht das XML mit LINQ to XML erstellen und dann .ToString () verwenden?
John Saunders
@ JohnSaunders, weil Roslyn seine eigenen XML-Klassen hat, wie z XmlElementSyntax. Und es wird auch durch die Tatsache kompliziert, dass Sie das auch generieren müssen ///. Und ich kann nicht jede Zeile als separate Zeile generieren XObject, da dies bei mehrzeiligen Tags nicht funktioniert.
Svick
1
@svick: Generieren Sie also die XML-Datei in einer Zeile, bleiben Sie ///davor und formatieren Sie den Code neu. Keine große Sache und sicherlich ein Eckfall. Wenn es absolut notwendig ist, können Sie sicher eine benutzerdefinierte Funktion erstellen XmlWriter, um Zeilenumbrüche und Leerzeichen nach Ihren Wünschen auszuführen, aber ///vor neuen Zeilen zu platzieren. Verwenden Sie alternativ ein XSLT, um das XML hübsch auszudrucken. In jedem Fall sollte XML dennoch von einer XML-API generiert werden.
John Saunders
5

Und wenn Sie, wie ich, als ich diese Frage gefunden habe, XML-Knotennamen umgehen möchten, wie zum Beispiel beim Lesen aus einer XML-Serialisierung, verwenden Sie den einfachsten Weg:

XmlConvert.EncodeName(string nameToEscape)

Leerzeichen und ungültige Zeichen für XML-Elemente werden ebenfalls ausgeblendet.

http://msdn.microsoft.com/en-us/library/system.security.securityelement.escape%28VS.80%29.aspx

Charlie Brown
quelle
Ich denke, basierend auf den Fragen, dass sie nur inneren Text wollen. Ihre Lösung wird funktionieren, ist aber etwas übertrieben, da sie auch Dinge wie Element- und Attributnamen behandeln soll. \
Sean Duggan
Nun, ich bin hierher gekommen, um Knotennamen zu entkommen, und dachte, meine Erkenntnisse könnten in Zukunft jedem helfen. Ich sehe auch nicht, was der "Overkill" ist, aber es ist in Ordnung. ;)
CharlieBrown
Oh, es sind nützliche Informationen. :) Ich dachte nur, ich möchte darauf hinweisen, dass einer der Gründe, warum Sie möglicherweise nicht positiv bewertet wurden, darin besteht, dass die Leute das Gefühl haben, dass Sie die vorliegende Frage nicht beantworten.
Sean Duggan
Der Link führt zu Dokumenten für SecurityElement.Escape (String). War dies beabsichtigt? XmlConvert.EncodeName (String) hat eine eigene Seite. Ich weiß, dass es einige Jahre her ist, seit dies gefragt wurde, aber woher weiß ich, welches ich verwenden soll? Tun sie nicht dasselbe, aber auf unterschiedliche Weise?
Micnil
4

WARNUNG: Nekromantie

Die Antwort von Darin Dimitrov + System.Security.SecurityElement.Escape (Zeichenfolge) ist immer noch nicht vollständig.

In XML 1.1 besteht der einfachste und sicherste Weg darin, ALLES zu codieren.
Wie &#09;für \ t.
Es wird in XML 1.0 überhaupt nicht unterstützt.
Für XML 1.0 besteht eine mögliche Problemumgehung darin, den Text, der die Zeichen enthält, mit Base-64 zu codieren.

//string EncodedXml = SpecialXmlEscape("привет мир");
//Console.WriteLine(EncodedXml);
//string DecodedXml = XmlUnescape(EncodedXml);
//Console.WriteLine(DecodedXml);
public static string SpecialXmlEscape(string input)
{
    //string content = System.Xml.XmlConvert.EncodeName("\t");
    //string content = System.Security.SecurityElement.Escape("\t");
    //string strDelimiter = System.Web.HttpUtility.HtmlEncode("\t"); // XmlEscape("\t"); //XmlDecode("&#09;");
    //strDelimiter = XmlUnescape("&#59;");
    //Console.WriteLine(strDelimiter);
    //Console.WriteLine(string.Format("&#{0};", (int)';'));
    //Console.WriteLine(System.Text.Encoding.ASCII.HeaderName);
    //Console.WriteLine(System.Text.Encoding.UTF8.HeaderName);


    string strXmlText = "";

    if (string.IsNullOrEmpty(input))
        return input;


    System.Text.StringBuilder sb = new StringBuilder();

    for (int i = 0; i < input.Length; ++i)
    {
        sb.AppendFormat("&#{0};", (int)input[i]);
    }

    strXmlText = sb.ToString();
    sb.Clear();
    sb = null;

    return strXmlText;
} // End Function SpecialXmlEscape

XML 1.0:

public static string Base64Encode(string plainText)
{
    var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
    return System.Convert.ToBase64String(plainTextBytes);
}

public static string Base64Decode(string base64EncodedData)
{
    var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
    return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
Stefan Steiger
quelle
Wie entkommen Sie in XML 1.1 allem?
Philip Pittle
@ Philip Pittle: Siehe SpecialXmlEscape
Stefan Steiger
4

Eine weitere Einstellung, die auf John Skeets Antwort basiert und die Tags nicht zurückgibt :

void Main()
{
    XmlString("Brackets & stuff <> and \"quotes\"").Dump();
}

public string XmlString(string text)
{
    return new XElement("t", text).LastNode.ToString();
} 

Dies gibt nur den übergebenen Wert im XML-codierten Format zurück:

Brackets &amp; stuff &lt;&gt; and "quotes"
Rick Strahl
quelle
3

Die folgenden Funktionen erledigen die Arbeit. Ich habe nicht gegen XmlDocument getestet, aber ich denke, das ist viel schneller.

public static string XmlEncode(string value)
{
    System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings 
    {
        ConformanceLevel = System.Xml.ConformanceLevel.Fragment
    };

    StringBuilder builder = new StringBuilder();

    using (var writer = System.Xml.XmlWriter.Create(builder, settings))
    {
        writer.WriteString(value);
    }

    return builder.ToString();
}

public static string XmlDecode(string xmlEncodedValue)
{
    System.Xml.XmlReaderSettings settings = new System.Xml.XmlReaderSettings
    {
        ConformanceLevel = System.Xml.ConformanceLevel.Fragment
    };

    using (var stringReader = new System.IO.StringReader(xmlEncodedValue))
    {
        using (var xmlReader = System.Xml.XmlReader.Create(stringReader, settings))
        {
            xmlReader.Read();
            return xmlReader.Value;
        }
    }
}
Ramazan Binarbasi
quelle
2

Verwenden einer Bibliothek eines Drittanbieters ( Newtonsoft.Json ) als Alternative:

public static string XmlEncode(string unescaped)
{
    if (unescaped == null) return null;
    return JsonConvert.SerializeObject(unescaped); ;
}

public static string XmlDecode(string escaped)
{
    if (escaped == null) return null;
    return JsonConvert.DeserializeObject(escaped, typeof(string)).ToString();
}

Beispiel:

a<b <==> "a&lt;b"

<foo></foo> <==> "foo&gt;&lt;/foo&gt;"

abberdeen
quelle