Formatieren Sie die XML-Zeichenfolge, um eine freundliche XML-Zeichenfolge zu drucken

178

Ich habe eine XML-Zeichenfolge als solche:

<?xml version='1.0'?><response><error code='1'> Success</error></response>

Es gibt keine Linien zwischen einem Element und einem anderen und ist daher sehr schwer zu lesen. Ich möchte eine Funktion, die die obige Zeichenfolge formatiert:

<?xml version='1.0'?>
<response>
<error code='1'> Success</error>
</response> 

Gibt es eine .Net-Bibliothek oder ein Code-Snippet, die ich ohne weiteres verwenden kann, ohne die Formatfunktion selbst manuell zu schreiben?

Graviton
quelle
1
Requisiten an CMS, Frage ist ein Duplikat stackoverflow.com/questions/203528
Spence
2
Kein Duplikat. Dieser gibt an, XmlDocumentwelche die am höchsten bewertete Antwort auf diese Frage disqualifizieren würde.
Sirdank

Antworten:

185

Verwenden Sie XmlTextWriter...

public static string PrintXML(string xml)
{
    string result = "";

    MemoryStream mStream = new MemoryStream();
    XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode);
    XmlDocument document = new XmlDocument();

    try
    {
        // Load the XmlDocument with the XML.
        document.LoadXml(xml);

        writer.Formatting = Formatting.Indented;

        // Write the XML into a formatting XmlTextWriter
        document.WriteContentTo(writer);
        writer.Flush();
        mStream.Flush();

        // Have to rewind the MemoryStream in order to read
        // its contents.
        mStream.Position = 0;

        // Read MemoryStream contents into a StreamReader.
        StreamReader sReader = new StreamReader(mStream);

        // Extract the text from the StreamReader.
        string formattedXml = sReader.ReadToEnd();

        result = formattedXml;
    }
    catch (XmlException)
    {
        // Handle the exception
    }

    mStream.Close();
    writer.Close();

    return result;
}
SM Kamran
quelle
7
Dies funktioniert, wenn Sie mit Code arbeiten, der sich in einer alten Version des .NET Frameworks vor LINQ befindet, das andere Beispiel jedoch viel sauberer ist.
Mike
8
Um Mikes Kommentar zu verdeutlichen: LINQ wurde in .NET 3.5 eingeführt. Wenn Sie also eine ältere Version von .NET verwenden (.NET 1, 1.1, 2 oder 3.0), müssen Sie diese Antwort verwenden. Wenn Sie jedoch .NET 3.5 oder höher verwenden, ist die Antwort von Charles Prakash Dasari viel einfacher.
Simon Tewsi
1
@SM Kamran Ich verwende Ihren Code, erhalte jedoch die Fehlermeldung {"Kann nicht auf einen geschlossenen Stream zugreifen."} Auf writer.Close (); Bitte geben Sie Lösung.
Jatin Gadhiya
@JatinGadhiya Ich hatte das gleiche Problem und habe es gelöst, indem ich {using block} zum Definieren der Streams verwendet habe. Auf diese Weise müssen Sie den Stream nicht manuell schließen, und Streams werden automatisch geschlossen, wenn das Ende des using-Blocks erreicht ist.
Vahid Farahmandian
312

Sie müssen den Inhalt irgendwie analysieren ... Ich finde die Verwendung von LINQ der einfachste Weg, dies zu tun. Auch hier hängt alles von Ihrem genauen Szenario ab. Hier ist ein Arbeitsbeispiel mit LINQ zum Formatieren einer XML-Eingabezeichenfolge.

string FormatXml(string xml)
{
     try
     {
         XDocument doc = XDocument.Parse(xml);
         return doc.ToString();
     }
     catch (Exception)
     {
         // Handle and throw if fatal exception here; don't just ignore them
         return xml;
     }
 }

[using-Anweisungen werden der Kürze halber weggelassen]

Charles Prakash Dasari
quelle
Betrifft dies ausschließlich Zeilenumbrüche und Einrückungen? Ich möchte keine anderen Änderungen, wie z. B. "0" in "0.0" usw. Wenn alle Leerzeichen entfernt werden, möchte ich, dass die gestrippte Ergebniszeichenfolge genau mit der gestrippten Eingabezeichenfolge übereinstimmt.
Radim Cernej
3
@ Radim Ja. Es werden keine Änderungen an den tatsächlichen Daten vorgenommen. Es werden nur Tags formatiert und eingerückt.
Charles Prakash Dasari
2
Ich habe festgestellt, dass es mit UTF8 gut funktioniert hat, aber nicht mit Unicode-XML-Dateiinhalten.
Nayan
1
@SteveWellens können Sie über doc.Declaration.ToString() + doc.ToString()oder mit doc.Saveanstelle von auf die Deklaration zugreifen doc.ToString. Siehe diesen Link für weitere Details.
David French
1
Schlagen Sie vor, die Namespaces einzubeziehen, da Benutzer nicht nach einem Namespace für eine Klasse suchen müssen, die sie zuvor möglicherweise nicht häufig verwendet haben. using System.Xml.Linq; Funktioniert gut Danke!
Scott Moniz
61

Dieser von kristopherjohnson ist haufenweise besser:

  1. Es ist auch kein XML-Dokumentkopf erforderlich.
  2. Hat klarere Ausnahmen
  3. Fügt zusätzliche Verhaltensoptionen hinzu: OmitXmlDeclaration = true, NewLineOnAttributes = true
  4. Weniger Codezeilen

    static string PrettyXml(string xml)
    {
        var stringBuilder = new StringBuilder();
    
        var element = XElement.Parse(xml);
    
        var settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;
        settings.Indent = true;
        settings.NewLineOnAttributes = true;
    
        using (var xmlWriter = XmlWriter.Create(stringBuilder, settings))
        {
            element.Save(xmlWriter);
        }
    
        return stringBuilder.ToString();
    }
Todd
quelle
Todd, könnten Sie klarstellen, was Sie unter "erfordert keinen XML-Dokumentenkopf" verstehen? Ich habe die Lösung von Charles Prakash Dasari ausprobiert und gerade ein XML-Fragment ohne XML-Deklaration (dh ohne die <?xml version="1.0" encoding="UTF-8" ?>Zeile oben) übergeben, und es hat gut funktioniert.
Simon Tewsi
3
Im Vergleich zur akzeptierten Antwort. Im Vergleich zu Charles hätte dieser eine bessere Konfigurierbarkeit. Allerdings würde ich wahrscheinlich in Zukunft selbst die Charlies-Methode verwenden, eine solche Konfigurierbarkeit wäre eine seltene Voraussetzung.
Todd
1
Dieser ist viel viel besser und kürzer
Alex Jolig
8

Die einfache Lösung, die für mich funktioniert:

        XmlDocument xmlDoc = new XmlDocument();
        StringWriter sw = new StringWriter();
        xmlDoc.LoadXml(rawStringXML);
        xmlDoc.Save(sw);
        String formattedXml = sw.ToString();
ZeeProgrammer
quelle
Dadurch wird eine XML-Datei mit <? xml version = "1.0" encoding = "utf-16"?> als Header erstellt. Dies wurde von XmlSerializer nicht mit dem Fehler "Es gibt keine Unicode-Bytereihenfolge" analysiert. Das Update bestand darin, die Codierung = "utf-16" zu entfernen, siehe: stackoverflow.com/questions/29915467/… .
Declan Taylor
6

Überprüfen Sie den folgenden Link: So drucken Sie XML hübsch aus (Leider gibt der Link jetzt 404 zurück :()

Die Methode im Link verwendet eine XML-Zeichenfolge als Argument und gibt eine wohlgeformte (eingerückte) XML-Zeichenfolge zurück.

Ich habe gerade den Beispielcode aus dem Link kopiert, um diese Antwort umfassender und bequemer zu gestalten.

public static String PrettyPrint(String XML)
{
    String Result = "";

    MemoryStream MS = new MemoryStream();
    XmlTextWriter W = new XmlTextWriter(MS, Encoding.Unicode);
    XmlDocument D   = new XmlDocument();

    try
    {
        // Load the XmlDocument with the XML.
        D.LoadXml(XML);

        W.Formatting = Formatting.Indented;

        // Write the XML into a formatting XmlTextWriter
        D.WriteContentTo(W);
        W.Flush();
        MS.Flush();

        // Have to rewind the MemoryStream in order to read
        // its contents.
        MS.Position = 0;

        // Read MemoryStream contents into a StreamReader.
        StreamReader SR = new StreamReader(MS);

        // Extract the text from the StreamReader.
        String FormattedXML = SR.ReadToEnd();

        Result = FormattedXML;
    }
    catch (XmlException)
    {
    }

    MS.Close();
    W.Close();

    return Result;
}
Chansik Im
quelle
2
Funktioniert hervorragend für mich, ich habe es gerade zu einer Erweiterungsmethode für Zeichenfolgen gemacht. Auch diese Website ist nicht verfügbar, also ist es gut, dass Sie sich eine Kopie
geschnappt haben
1
Doppelte Antwort. @SM Kamran postet die gleiche Antwort auch.
Vahid Farahmandian
@VahidFarahmandian Ja. Ich konnte nicht viel dagegen tun, weil ich 1 Minute früher als er gepostet habe :) Übrigens habe ich versucht hinzuzufügen, woher die Antwort kam, um dem Blog-Poster die Ehre zu geben. Leider ist der Link jetzt defekt :(.
Chansik Im
Ich mag diese Antwort am besten im Vergleich zu der von Charles (FormatXml) und Todd (PrettyXml), weil diese Antwort die <?xml...?>Linie nicht streift . Diese Antwort entspricht dem, was ich ursprünglich im Sinn hatte. Das einzig Negative wäre, dass ich Tabulatoren gegenüber nativ verwendeten Leerzeichen vorziehen würde. Ich setze Indentation = 1und IndentChar = '\t'bekomme genau das, was ich wollte.
Sarah Weinberger
@ CHICoder007 Vielen Dank für den Kommentar zur Erweiterungsmethode. Du hast mir etwas Neues beigebracht. Das Hinzufügen eines (this String XML)funktioniert hervorragend.
Sarah Weinberger
4

Ich habe es versucht:

internal static void IndentedNewWSDLString(string filePath)
{
    var xml = File.ReadAllText(filePath);
    XDocument doc = XDocument.Parse(xml);
    File.WriteAllText(filePath, doc.ToString());
}

es funktioniert gut wie erwartet.

Akhilesh singh
quelle
aber dies entfernt das <? xml?> Tag oben
Juran
2

.NET 2.0 ignoriert das Auflösen von Namen und verfügt über die richtige Ressourcenentsorgung, Einrückung, Aufbewahrung von Leerzeichen und benutzerdefinierte Codierung :

public static string Beautify(System.Xml.XmlDocument doc)
{
    string strRetValue = null;
    System.Text.Encoding enc = System.Text.Encoding.UTF8;
    // enc = new System.Text.UTF8Encoding(false);

    System.Xml.XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings();
    xmlWriterSettings.Encoding = enc;
    xmlWriterSettings.Indent = true;
    xmlWriterSettings.IndentChars = "    ";
    xmlWriterSettings.NewLineChars = "\r\n";
    xmlWriterSettings.NewLineHandling = System.Xml.NewLineHandling.Replace;
    //xmlWriterSettings.OmitXmlDeclaration = true;
    xmlWriterSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document;


    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
    {
        using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(ms, xmlWriterSettings))
        {
            doc.Save(writer);
            writer.Flush();
            ms.Flush();

            writer.Close();
        } // End Using writer

        ms.Position = 0;
        using (System.IO.StreamReader sr = new System.IO.StreamReader(ms, enc))
        {
            // Extract the text from the StreamReader.
            strRetValue = sr.ReadToEnd();

            sr.Close();
        } // End Using sr

        ms.Close();
    } // End Using ms


    /*
    System.Text.StringBuilder sb = new System.Text.StringBuilder(); // Always yields UTF-16, no matter the set encoding
    using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sb, settings))
    {
        doc.Save(writer);
        writer.Close();
    } // End Using writer
    strRetValue = sb.ToString();
    sb.Length = 0;
    sb = null;
    */

    xmlWriterSettings = null;
    return strRetValue;
} // End Function Beautify

Verwendung:

System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("C:\Test.svg");
string SVG = Beautify(xmlDoc);
Stefan Steiger
quelle
0

Wenn Sie das XMLDoc laden, bin ich mir ziemlich sicher, dass die .ToString () -Funktion dafür eine Überladung aufweist.

Aber ist das zum Debuggen? Der Grund dafür, dass es so gesendet wird, ist, dass es weniger Speicherplatz beansprucht (dh unnötiges Leerzeichen aus dem XML entfernt).

Spence
quelle
0

Anpassbare hübsche XML-Ausgabe mit UTF-8-XML-Deklaration

Die folgende Klassendefinition bietet eine einfache Methode zum Konvertieren einer Eingabe-XML-Zeichenfolge in formatiertes Ausgabe-XML mit der XML-Deklaration als UTF-8. Es unterstützt alle Konfigurationsoptionen, die die XmlWriterSettings- Klasse bietet.

using System;
using System.Text;
using System.Xml;
using System.IO;

namespace CJBS.Demo
{
    /// <summary>
    /// Supports formatting for XML in a format that is easily human-readable.
    /// </summary>
    public static class PrettyXmlFormatter
    {

        /// <summary>
        /// Generates formatted UTF-8 XML for the content in the <paramref name="doc"/>
        /// </summary>
        /// <param name="doc">XmlDocument for which content will be returned as a formatted string</param>
        /// <returns>Formatted (indented) XML string</returns>
        public static string GetPrettyXml(XmlDocument doc)
        {
            // Configure how XML is to be formatted
            XmlWriterSettings settings = new XmlWriterSettings 
            {
                Indent = true
                , IndentChars = "  "
                , NewLineChars = System.Environment.NewLine
                , NewLineHandling = NewLineHandling.Replace
                //,NewLineOnAttributes = true
                //,OmitXmlDeclaration = false
            };

            // Use wrapper class that supports UTF-8 encoding
            StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8);

            // Output formatted XML to StringWriter
            using (XmlWriter writer = XmlWriter.Create(sw, settings))
            {
                doc.Save(writer);
            }

            // Get formatted text from writer
            return sw.ToString();
        }



        /// <summary>
        /// Wrapper class around <see cref="StringWriter"/> that supports encoding.
        /// Attribution: http://stackoverflow.com/a/427737/3063884
        /// </summary>
        private sealed class StringWriterWithEncoding : StringWriter
        {
            private readonly Encoding encoding;

            /// <summary>
            /// Creates a new <see cref="PrettyXmlFormatter"/> with the specified encoding
            /// </summary>
            /// <param name="encoding"></param>
            public StringWriterWithEncoding(Encoding encoding)
            {
                this.encoding = encoding;
            }

            /// <summary>
            /// Encoding to use when dealing with text
            /// </summary>
            public override Encoding Encoding
            {
                get { return encoding; }
            }
        }
    }
}

Möglichkeiten zur weiteren Verbesserung: -

  • Es GetPrettyXml(XmlDocument doc, XmlWriterSettings settings)könnte eine zusätzliche Methode erstellt werden, mit der der Aufrufer die Ausgabe anpassen kann.
  • Es GetPrettyXml(String rawXml)könnte eine zusätzliche Methode hinzugefügt werden, die das Parsen von Rohtext unterstützt, anstatt den Client das XmlDocument verwenden zu lassen. In meinem Fall musste ich das XML mit dem XmlDocument bearbeiten, daher habe ich dies nicht hinzugefügt.

Verwendung:

String myFormattedXml = null;
XmlDocument doc = new XmlDocument();
try
{
    doc.LoadXml(myRawXmlString);
    myFormattedXml = PrettyXmlFormatter.GetPrettyXml(doc);
}
catch(XmlException ex)
{
    // Failed to parse XML -- use original XML as formatted XML
    myFormattedXml = myRawXmlString;
}
CJBS
quelle