Formatta la stringa XML per stampare una stringa XML intuitiva


178

Ho una stringa XML in quanto tale:

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

Non ci sono linee tra un elemento e l'altro, quindi è molto difficile da leggere. Voglio una funzione che formatta la stringa sopra:

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

Senza ricorrere a scrivere manualmente la funzione di formattazione, c'è qualche libreria .Net o frammento di codice che posso usare a mano?


1
puntelli al CMS, la domanda è uno stackoverflow.com/questions/203528
Spence

2
Non un duplicato. Quello specifica XmlDocumentquale sarebbe squalificare la risposta più votata su questa domanda.
sirdank,

Risposte:


185

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

7
Funziona se hai a che fare con codice che si trova su una versione precedente del framework .NET pre-LINQ, ma l'altro esempio è molto più pulito.
Mike

8
Per chiarire il commento di Mike: LINQ è stato introdotto in .NET 3.5. Quindi, se stai usando una versione di .NET precedente (.NET 1, 1.1, 2 o 3.0), dovrai usare questa risposta. Ma se stai usando .NET 3.5 o successivo, la risposta di Charles Prakash Dasari è molto più semplice.
Simon Tewsi,

1
@SM Kamran Sto usando il tuo codice ma ricevo un errore simile a {"Impossibile accedere a un flusso chiuso."} Su writer.Close (); per favore dai una soluzione.
Jatin Gadhiya,

@JatinGadhiya Ho avuto lo stesso problema e l'ho risolto usando {using block} nel definire i flussi. in tal modo non è necessario chiudere manualmente il flusso e gli stream verranno chiusi automaticamente quando si raggiunge la fine del blocco utilizzando.
Vahid Farahmandian,

312

Dovrai analizzare il contenuto in qualche modo ... Trovo che usare LINQ sia il modo più semplice per farlo. Ancora una volta, tutto dipende dal tuo esatto scenario. Ecco un esempio funzionante che utilizza LINQ per formattare una stringa XML di input.

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

[le dichiarazioni di utilizzo sono ommesse per brevità]


Questo influenzerà rigorosamente le interruzioni di riga e il rientro? Non voglio altre modifiche, come "0" che viene modificato in "0,0" ecc. Quando tutto lo spazio bianco viene rimosso, voglio che la stringa risultante eliminata sia esattamente la stessa della stringa di input eliminata.
Radim Cernej,

3
@radim Sì. Non verranno apportate modifiche ai dati effettivi. Solo i tag verranno formattati e rientrati.
Charles Prakash Dasari,

2
Ho notato che ha funzionato bene con UTF8, ma non con il contenuto del file XML Unicode.
Nayan,

1
@SteveWellens, è possibile accedere alla dichiarazione tramite doc.Declaration.ToString() + doc.ToString()o utilizzando doc.Saveinvece di doc.ToString. Vedi questo link per maggiori dettagli.
David French

1
Suggerisci di includere gli spazi dei nomi poiché impedisce agli utenti di cercare uno spazio dei nomi per una classe che potrebbero non aver usato molto prima. utilizzando System.Xml.Linq; Funziona bene Grazie!
Scott Moniz,

61

Questo, di Kristopherjohnson, è molto meglio:

  1. Non richiede nemmeno un'intestazione del documento XML.
  2. Ha eccezioni più chiare
  3. Aggiunge opzioni di comportamento extra: OmitXmlDeclaration = true, NewLineOnAttributes = true
  4. Meno righe di codice

    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, potresti chiarire cosa intendi con "non richiede un'intestazione di documento XML"? Ho provato la soluzione di Charles Prakash Dasari e ho appena passato un frammento XML senza una dichiarazione xml (cioè senza la <?xml version="1.0" encoding="UTF-8" ?>riga in alto) e ha funzionato bene.
Simon Tewsi,

3
Rispetto alla risposta accettata. Rispetto a Charles, questo avrebbe una migliore configurabilità. Tuttavia, probabilmente userò il metodo Charlies in futuro, tale configurabilità sarebbe un requisito raro.
Todd,

1
Questo è molto meglio e più breve
Alex Jolig

8

La semplice soluzione che funziona per me:

        XmlDocument xmlDoc = new XmlDocument();
        StringWriter sw = new StringWriter();
        xmlDoc.LoadXml(rawStringXML);
        xmlDoc.Save(sw);
        String formattedXml = sw.ToString();

questo crea un file xml con <? xml version = "1.0" encoding = "utf-16"?> come intestazione. Questo non è stato analizzato da XmlSerializer, con l'errore "Non esiste un contrassegno di ordine byte Unicode". La correzione consisteva nel rimuovere la codifica = "utf-16", vedere: stackoverflow.com/questions/29915467/… .
Declan Taylor,

6

Controlla il seguente link: Come stampare abbastanza XML (Sfortunatamente, il link ora restituisce 404 :()

Il metodo nel collegamento accetta una stringa XML come argomento e restituisce una stringa XML ben formata (rientrata).

Ho appena copiato il codice di esempio dal link per rendere questa risposta più completa e conveniente.

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

2
Funziona benissimo per me, l'ho appena reso un metodo di estensione della stringa. Anche quel sito web è inattivo, quindi è bello che tu ne abbia preso una copia ...
goodguys_activate

1
Risposta duplicata. @SM Kamran pubblica anche la stessa risposta.
Vahid Farahmandian,

@VahidFarahmandian Sì. Non potevo farci molto perché avevo pubblicato un minuto prima di lui :) A proposito, stavo cercando di aggiungere da dove proveniva la risposta per dare credito al poster del blog. Sfortunatamente, il collegamento è interrotto ora :(.
Chansik Im

Mi piace questa risposta la migliore rispetto a quella di Charles (FormatXml) e Todd (PrettyXml), perché questa risposta non elimina la <?xml...?>linea. Questa risposta mi fa venire in mente ciò che inizialmente avevo in mente. L'unico aspetto negativo sarebbe che preferirei le schede piuttosto che gli spazi usati in modo nativo. Ho impostato Indentation = 1e IndentChar = '\t'per ottenere esattamente quello che volevo.
Sarah Weinberger,

@ CHICoder007 Grazie per il commento sul metodo di estensione. Mi hai insegnato qualcosa di nuovo. Aggiungendo un (this String XML)grande funziona.
Sarah Weinberger,

4

Provai:

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

funziona bene come previsto.


ma questo rimuove il tag <? xml?> nella parte superiore
Juran,

2

.NET 2.0 ignora la risoluzione dei nomi e con un'adeguata eliminazione delle risorse, rientri, spazi bianchi e codifica personalizzata :

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

Uso:

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

0

se carichi XMLDoc sono abbastanza sicuro che la funzione .ToString () abbia un sovraccarico per questo.

Ma è per il debug? Il motivo per cui viene inviato in questo modo è quello di occupare meno spazio (es. Eliminando gli spazi bianchi non necessari dall'XML).


0

Output Pretty XML personalizzabile con dichiarazione XML UTF-8

La seguente definizione di classe fornisce un metodo semplice per convertire una stringa XML di input in XML di output formattato con la dichiarazione xml come UTF-8. Supporta tutte le opzioni di configurazione offerte dalla classe XmlWriterSettings .

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

Possibilità di ulteriore miglioramento: -

  • È GetPrettyXml(XmlDocument doc, XmlWriterSettings settings)possibile creare un metodo aggiuntivo che consente al chiamante di personalizzare l'output.
  • È possibile aggiungere un metodo GetPrettyXml(String rawXml)aggiuntivo che supporti l'analisi del testo non elaborato, anziché consentire al client di utilizzare XmlDocument. Nel mio caso, avevo bisogno di manipolare l'XML usando XmlDocument, quindi non l'ho aggiunto.

Uso:

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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.