web-dev-qa-db-fra.com

Échapper aux caractères XML non valides en C #

J'ai une chaîne qui contient des caractères XML non valides. Comment puis-je échapper (ou supprimer) des caractères XML non valides avant d'analyser la chaîne?

75
Alireza Noori

Pour supprimer les caractères XML invalides, je vous suggère d'utiliser la méthode XmlConvert.IsXmlChar . Il a été ajouté depuis .NET Framework 4 et est également présenté dans Silverlight. Voici le petit échantillon:

void Main() {
    string content = "\v\f\0";
    Console.WriteLine(IsValidXmlString(content)); // False

    content = RemoveInvalidXmlChars(content);
    Console.WriteLine(IsValidXmlString(content)); // True
}

static string RemoveInvalidXmlChars(string text) {
    var validXmlChars = text.Where(ch => XmlConvert.IsXmlChar(ch)).ToArray();
    return new string(validXmlChars);
}

static bool IsValidXmlString(string text) {
    try {
        XmlConvert.VerifyXmlChars(text);
        return true;
    } catch {
        return false;
    }
}

Et pour échapper aux caractères XML invalides, je vous suggère d'utiliser la méthode XmlConvert.EncodeName . Voici le petit échantillon:

void Main() {
    const string content = "\v\f\0";
    Console.WriteLine(IsValidXmlString(content)); // False

    string encoded = XmlConvert.EncodeName(content);
    Console.WriteLine(IsValidXmlString(encoded)); // True

    string decoded = XmlConvert.DecodeName(encoded);
    Console.WriteLine(content == decoded); // True
}

static bool IsValidXmlString(string text) {
    try {
        XmlConvert.VerifyXmlChars(text);
        return true;
    } catch {
        return false;
    }
}

Mise à jour: Il convient de mentionner que l'opération de codage produit une chaîne d'une longueur supérieure ou égale à la longueur d'une chaîne source. Cela peut être important lorsque vous stockez une chaîne codée dans une base de données dans une colonne de chaîne avec une limitation de longueur et que vous validez la longueur de la chaîne source dans votre application pour respecter la limitation des colonnes de données.

100
Igor Kustov

Utilisez SecurityElement.Escape

using System;
using System.Security;

class Sample {
  static void Main() {
    string text = "Escape characters : < > & \" \'";
    string xmlText = SecurityElement.Escape(text);
//output:
//Escape characters : &lt; &gt; &amp; &quot; &apos;
    Console.WriteLine(xmlText);
  }
}
61
BLUEPIXY

Si vous écrivez du XML, utilisez simplement les classes fournies par le framework pour créer le XML. Vous n'aurez pas à vous soucier de vous échapper ou quoi que ce soit.

Console.Write(new XElement("Data", "< > &"));

Sortie

<Data>&lt; &gt; &amp;</Data>

Si vous devez lire un fichier XML mal formé, ne le faites pas tilisez l'expression régulière. Au lieu de cela, utilisez le Html ​​Agility Pack .

19

La méthode RemoveInvalidXmlChars fournie par Irishman ne prend pas en charge les caractères de substitution. Pour le tester, utilisez l'exemple suivant:

static void Main()
{
    const string content = "\v\U00010330";

    string newContent = RemoveInvalidXmlChars(content);

    Console.WriteLine(newContent);
}

Cela retourne une chaîne vide mais cela ne devrait pas! Il doit renvoyer "\ U00010330" car le caractère + 103 est un caractère XML valide.

Pour supporter les caractères de substitution, je suggère d'utiliser la méthode suivante:

public static string RemoveInvalidXmlChars(string text)
{
    if (string.IsNullOrEmpty(text))
        return text;

    int length = text.Length;
    StringBuilder stringBuilder = new StringBuilder(length);

    for (int i = 0; i < length; ++i)
    {
        if (XmlConvert.IsXmlChar(text[i]))
        {
            stringBuilder.Append(text[i]);
        }
        else if (i + 1 < length && XmlConvert.IsXmlSurrogatePair(text[i + 1], text[i]))
        {
            stringBuilder.Append(text[i]);
            stringBuilder.Append(text[i + 1]);
            ++i;
        }
    }

    return stringBuilder.ToString();
}
4
Francois C

Voici une version optimisée de la méthode ci-dessus, RemoveInvalidXmlChars, qui ne crée pas de nouveau tableau à chaque appel, ce qui oblige inutilement le CPG à:

public static string RemoveInvalidXmlChars(string text)
{
    if (text == null)
        return text;
    if (text.Length == 0)
        return text;

    // a bit complicated, but avoids memory usage if not necessary
    StringBuilder result = null;
    for (int i = 0; i < text.Length; i++)
    {
        var ch = text[i];
        if (XmlConvert.IsXmlChar(ch))
        {
            result?.Append(ch);
        }
        else if (result == null)
        {
            result = new StringBuilder();
            result.Append(text.Substring(0, i));
        }
    }

    if (result == null)
        return text; // no invalid xml chars detected - return original text
    else
        return result.ToString();

}
4
Urs Meili
// Replace invalid characters with empty strings.
   Regex.Replace(inputString, @"[^\w\.@-]", ""); 

Le modèle d'expression régulière [^\w. @ -] correspond à tout caractère autre que Word, un point, un symbole @ ou un trait d'union. Un caractère Word est une lettre, un chiffre décimal ou un connecteur de ponctuation tel qu'un trait de soulignement. Tout caractère correspondant à ce modèle est remplacé par String.Empty, qui est la chaîne définie par le modèle de remplacement. Pour autoriser des caractères supplémentaires dans l'entrée utilisateur, ajoutez ces caractères à la classe de caractères dans le modèle d'expression régulière. Par exemple, le modèle d'expression régulière [^\w. @ - \%] autorise également un symbole de pourcentage et une barre oblique inverse dans une chaîne d'entrée.

Regex.Replace(inputString, @"[!@#$%_]", "");

Reportez-vous aussi:

Suppression des caractères non valides de la balise de nom XML - RegEx C #

Voici une fonction pour supprimer les caractères d'une chaîne XML spécifiée:

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace XMLUtils
{
    class Standards
    {
        /// <summary>
        /// Strips non-printable ascii characters 
        /// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
        /// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0
        /// </summary>
        /// <param name="content">contents</param>
        /// <param name="XMLVersion">XML Specification to use. Can be 1.0 or 1.1</param>
        private void StripIllegalXMLChars(string tmpContents, string XMLVersion)
        {    
            string pattern = String.Empty;
            switch (XMLVersion)
            {
                case "1.0":
                    pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F])";
                    break;
                case "1.1":
                    pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF])";
                    break;
                default:
                    throw new Exception("Error: Invalid XML Version!");
            }

            Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
            if (regex.IsMatch(tmpContents))
            {
                tmpContents = regex.Replace(tmpContents, String.Empty);
            }
            tmpContents = string.Empty;
        }
    }
}
1
Siva Charan
string XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)
{
    if (UnfilteredString == null)
        return string.Empty;

    return XmlConvert.EncodeName(UnfilteredString);
}

string XMLReadStringWithoutIllegalCharacters(string FilteredString)
{
    if (UnfilteredString == null)
        return string.Empty;

    return XmlConvert.DecodeName(UnfilteredString);
}

Cette méthode simple remplace les caractères non valides avec la même valeur mais acceptés dans le contexte XML.


Pour écrire une chaîne, utilisez XMLWriteStringWithoutIllegalCharacters (string UnfilteredString).
Pour lire une chaîne, utilisez XMLReadStringWithoutIllegalCharacters (string FilteredString).

0
Marco Concas