web-dev-qa-db-fra.com

Échappement de chaîne en XML

Existe-t-il une fonction C # qui pourrait être utilisée pour échapper et dé-échapper une chaîne, qui pourrait être utilisée pour remplir le contenu d'un élément XML?

J'utilise VSTS 2008 + C # + .Net 3.0.

EDIT 1: Je concatène un fichier XML simple et court et je n’utilise pas la sérialisation. Je dois donc explicitement échapper manuellement le caractère XML. Par exemple, j’ai besoin de mettre a<b en <foo></foo>, j'ai donc besoin d'une chaîne d'échappement a<b et le mettre dans l'élément foo.

88
George2
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;
}
71
Darin Dimitrov
118
Dana Holt

EDIT: Vous dites "Je concatène un fichier XML simple et court et je n’utilise pas la sérialisation, il faut donc que nous échappions explicitement le caractère XML à la main".

Je vous conseillerais fortement de ne pas le faire à la main. Utilisez les API XML pour tout faire à votre place: lisez les fichiers d'origine, fusionnez les deux en un seul document, selon vos besoins (vous souhaiterez probablement utiliser XmlDocument.ImportNode), puis écrivez-le à nouveau. Vous ne voulez pas écrire vos propres analyseurs/formateurs XML. La sérialisation est quelque peu hors de propos ici.

Si vous pouvez nous donner un exemple bref mais complet de ce que vous essayez de faire, nous pourrons probablement vous aider à ne pas avoir à craindre de vous échapper.


réponse originale

Ce que vous voulez dire n'est pas tout à fait clair, mais normalement, les API XML le font pour vous. Vous définissez le texte dans un nœud, qui échappera automatiquement à tout ce dont il a besoin. Par exemple:

Exemple LINQ to XML:

using System;
using System.Xml.Linq;

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

        Console.WriteLine(element);
    }
}

exemple de DOM:

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

sortie des deux exemples:

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

Cela suppose que vous souhaitiez échapper à XML, bien sûr. Si vous ne l'êtes pas, merci de poster plus de détails.

37
Jon Skeet

Merci à @sehe pour l'évasion d'une ligne:

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

J'y ajoute le un-escape un-escape:

var unescapedAgain = System.Xml.XmlReader.Create(new StringReader("<r>" + escaped + "</r>")).ReadElementString();
24
Keith Robertson

George, c'est simple. Utilisez toujours les API XML pour gérer XML. Ils font tout ce qui vous échappe et vous échappe.

Ne créez jamais de XML en ajoutant des chaînes.

8
John Saunders

Et si vous voulez, comme moi lorsque j'ai trouvé cette question, échapper aux noms de nœud XML, comme par exemple lors de la lecture d'une sérialisation XML, utilisez le moyen le plus simple:

XmlConvert.EncodeName(string nameToEscape)

Il échappera également aux espaces et à tous les caractères non valides pour les éléments XML.

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

4
CharlieBrown

AVERTISSEMENT: Nécromancien

La réponse de Darin Dimitrov + System.Security.SecurityElement.Escape (string s) n'est toujours pas complète.

Dans XML 1.1, le moyen le plus simple et le plus sûr consiste simplement à encoder TOUT.
Comme &#09; pour\t.
Il n'est pas du tout pris en charge dans XML 1.0.
Pour XML 1.0, une solution de contournement possible consiste à coder en base 64 le texte contenant le (s) caractère (s).

//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);
}
3
Stefan Steiger

Utilisation d'une bibliothèque tierce ( Newtonsoft.Json ) comme 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();
}

Exemple:

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

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

2
Los Pollos Hermanos

Les fonctions suivantes feront le travail. N'a pas testé contre XmlDocument, mais j'imagine que c'est beaucoup plus rapide.

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;
        }
    }
}
2
Ramazan Binarbasi

Une autre prise basée sur la réponse de John Skeet selon laquelle ne renvoie pas les balises:

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

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

Ceci ne renvoie que la valeur transmise, au format XML:

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