Escape ungültige XML-Zeichen in C #

83

Ich habe eine Zeichenfolge, die ungültige XML-Zeichen enthält. Wie kann ich ungültige XML-Zeichen maskieren (oder entfernen), bevor ich die Zeichenfolge analysiere?

Alireza Noori
quelle
2
Könnten Sie mehr Kontext bereitstellen? Eine Beispieleingabe und eine Beispielausgabe. Auch was beabsichtigen Sie mit der Ausgabe zu tun.
Darin Dimitrov
5
Schreiben Sie das XML? Oder versuchen Sie, XML zu lesen, das eigentlich kein XML ist?
Marc Gravell
3
Verwenden Sie einen XmlWriter, es wird die ungültigen Zeichen für Sie entkommen
Thomas Levesque
2
@alireza Sie erhalten weitere nützliche Antworten, wenn Sie die Fragen beantworten, die Ihnen (für weitere Informationen) hier in den Kommentaren gestellt werden ...
Marc Gravell
Es tut mir Leid. Ich war ein paar Stunden weg. Bitte lesen Sie die Frage, die zu dieser führte: stackoverflow.com/questions/8330619/… Sie erhalten dort alle Informationen, die Sie benötigen
Alireza Noori

Antworten:

112

Um ungültige XML-Zeichen zu entfernen, empfehle ich die Verwendung der XmlConvert.IsXmlChar- Methode. Es wurde seit .NET Framework 4 hinzugefügt und wird auch in Silverlight dargestellt. Hier ist das kleine Beispiel:

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

Um ungültigen XML-Zeichen zu entgehen, empfehle ich die Verwendung der XmlConvert.EncodeName- Methode. Hier ist das kleine Beispiel:

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

Update: Es sollte erwähnt werden, dass die Codierungsoperation eine Zeichenfolge mit einer Länge erzeugt, die größer oder gleich einer Länge einer Quellzeichenfolge ist. Dies kann wichtig sein, wenn Sie eine codierte Zeichenfolge in einer Datenbank in einer Zeichenfolgenspalte mit Längenbeschränkung speichern und die Länge der Quellzeichenfolge in Ihrer App überprüfen, um sie an die Beschränkung der Datenspalten anzupassen.

Igor Kustov
quelle
XmlConvert.VerifyXmlCharslöst keine Ausnahme aus, wenn das Argument ungültige Zeichen enthält, sondern gibt die Nullzeichenfolge zurück (und gibt das Argument zurück, wenn alle enthaltenen Zeichen gültig sind). Versuchen Sie es einfach return XmlConvert.VerifyXmlChars (text) != null.
Matt Enright
3
@IgorKustov Mein schlechtes! Die Rückgabewertdokumentation scheint dem zu widersprechen, danke, dass Sie mich erwischt haben.
Matt Enright
3
Achten Sie darauf, XmlConvert.EncodeName nicht zu verwenden, wenn die Zeichenfolge für den XML-Wert bestimmt ist. Die Einschränkungen für XML-Namen sind strenger als die Einschränkungen für XML-Werte, und die Namenscodierung führt zu unnötigem unerwartetem Escape.
David Burg
1
@arik Mein Code dient nur zu Demonstrationszwecken, um den Status einer XML-Zeichenfolge vor und nach der Transformation anzuzeigen. Offensichtlich müssen Sie Ihren Code in Ihrem Code nicht validieren.
Igor Kustov
66

Verwenden Sie 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);
  }
}
BLUEPIXY
quelle
11
Dies entgeht keinen Steuerzeichen (wie char 30).
Zimdanen
19

Wenn Sie XML schreiben, verwenden Sie einfach die vom Framework bereitgestellten Klassen, um die XML zu erstellen. Sie müssen sich nicht um Flucht oder ähnliches kümmern.

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

Wird ausgegeben

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

Wenn Sie eine XML - Datei zu lesen , die ungültig ist, nicht verwendet regulären Ausdruck. Verwenden Sie stattdessen das HTML Agility Pack .

Pierre-Alain Vigeant
quelle
Nett. Haben Sie eine äquivalente Methode für jemanden, der XmlElement verwendet?
Djdanlib
3
Update: Das Festlegen der InnerText-Eigenschaft eines XmlElement scheint die Dinge korrekt zu umgehen. Beantwortete meine eigene Frage, huzzah!
Djdanlib
Also ist deine XML falsch geformt? wie <Data>&</Data>?
Pierre-Alain Vigeant
2
Ja, das ist genau das Problem.
Alireza Noori
2
Sie können immer noch Probleme bekommen, wenn der Inhalt Ihrer Elemente ungültige Zeichen wie Rücktaste (0x08), viele andere Steuerzeichen oder Ersatzcodepunkte enthält.
Jakubiszon
6

Die von Irishman bereitgestellte RemoveInvalidXmlChars-Methode unterstützt keine Ersatzzeichen. Verwenden Sie zum Testen das folgende Beispiel:

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

    string newContent = RemoveInvalidXmlChars(content);

    Console.WriteLine(newContent);
}

Dies gibt eine leere Zeichenfolge zurück, sollte es aber nicht! Es sollte "\ U00010330" zurückgeben, da das Zeichen U + 10330 ein gültiges XML-Zeichen ist.

Um Ersatzzeichen zu unterstützen, empfehle ich die folgende Methode:

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();
}
Francois C.
quelle
4

Hier ist eine optimierte Version der oben genannten Methode RemoveInvalidXmlChars, die nicht bei jedem Aufruf ein neues Array erstellt, wodurch der GC unnötig belastet wird:

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

}
Urs Meili
quelle
Was ist diese ?.Syntax? in der Schlange result?.Append(ch);?
JB. Mit Monica.
1
?.ist das Null-Conditional Operator. docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
Pure.Krome
1
// Replace invalid characters with empty strings.
   Regex.Replace(inputString, @"[^\w\.@-]", ""); 

Das Muster für reguläre Ausdrücke [^ \ w. @ -] entspricht jedem Zeichen, das kein Wortzeichen, kein Punkt, kein @ -Symbol oder kein Bindestrich ist. Ein Wortzeichen ist ein beliebiger Buchstabe, eine Dezimalstelle oder ein Satzzeichen, z. B. ein Unterstrich. Jedes Zeichen, das diesem Muster entspricht, wird durch String.Empty ersetzt. Dies ist die Zeichenfolge, die durch das Ersetzungsmuster definiert wird. Um zusätzliche Zeichen in der Benutzereingabe zuzulassen, fügen Sie diese Zeichen der Zeichenklasse im Muster für reguläre Ausdrücke hinzu. Das Muster für reguläre Ausdrücke [^ \ w. @ - \%] ermöglicht beispielsweise auch ein Prozentzeichen und einen Backslash in einer Eingabezeichenfolge.

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

Siehe auch dies:

Ungültige Zeichen aus dem XML-Namensschild entfernen - RegEx C #

Hier ist eine Funktion zum Entfernen der Zeichen aus einer angegebenen XML-Zeichenfolge:

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;
        }
    }
}
Siva Charan
quelle
0
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);
}

Diese einfache Methode ersetzt die ungültigen Zeichen durch denselben Wert, wird jedoch im XML-Kontext akzeptiert.


Verwenden Sie zum Schreiben einer Zeichenfolge XMLWriteStringWithoutIllegalCharacters (Zeichenfolge UnfilteredString).
Verwenden Sie zum Lesen von Zeichenfolgen XMLReadStringWithoutIllegalCharacters (Zeichenfolge FilteredString).

Marco Concas
quelle