Memformat string XML untuk mencetak string XML yang bersahabat

178

Saya memiliki string XML:

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

Tidak ada garis antara satu elemen dengan elemen lainnya, dan karenanya sangat sulit dibaca. Saya ingin fungsi yang memformat string di atas:

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

Tanpa harus menggunakan fungsi format secara manual, apakah ada .Net library atau potongan kode yang bisa saya gunakan begitu saja?

Graviton
sumber
1
alat peraga untuk CMS, pertanyaannya adalah duplikat stackoverflow.com/questions/203528
Spence
2
Bukan duplikat. Yang itu menentukan XmlDocumentmana yang akan mendiskualifikasi jawaban dengan suara tertinggi pada pertanyaan ini.
sirdank

Jawaban:

185

Gunakan 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
sumber
7
Ini berfungsi jika Anda berurusan dengan kode yang ada pada versi lama dari .NET framework pra-LINQ, tetapi contoh lainnya jauh lebih bersih.
Mike
8
Untuk mengklarifikasi komentar Mike: LINQ diperkenalkan di .NET 3.5. Jadi, jika Anda menggunakan versi .NET yang lebih lama dari itu (.NET 1, 1.1, 2 atau 3.0) maka Anda harus menggunakan jawaban ini. Tetapi jika Anda menggunakan .NET 3.5 atau lebih baru, jawaban Charles Prakash Dasari jauh lebih sederhana.
Simon Tewsi
1
@ SM Kamran saya menggunakan kode Anda tetapi saya mendapatkan tampilan kesalahan seperti {"Tidak dapat mengakses Aliran tertutup."} Pada writer.Close (); tolong beri solusi.
Jatin Gadhiya
@ JatinGadhiya Saya memiliki masalah yang sama dan saya mengatasinya dengan menggunakan {using block} dalam mendefinisikan stream. Sedemikian rupa Anda tidak perlu menutup aliran secara manual dan aliran akan ditutup secara otomatis ketika mencapai akhir blok menggunakan.
Vahid Farahmandian
312

Anda harus mem-parsing kontennya ... Saya menemukan menggunakan LINQ cara paling mudah untuk melakukannya. Sekali lagi, semuanya tergantung pada skenario persis Anda. Berikut adalah contoh yang berfungsi menggunakan LINQ untuk memformat string XML 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;
     }
 }

[menggunakan pernyataan dikomitmenkan untuk singkatnya]

Charles Prakash Dasari
sumber
Apakah ini akan memengaruhi pemisah baris dan lekukan? Saya tidak ingin ada perubahan lain, seperti "0" diubah menjadi "0,0" dll. Ketika semua spasi kosong dilucuti, saya ingin string hasil yang dilucuti persis sama dengan string input yang dilucuti.
Radim Cernej
3
@radim Ya. Tidak ada perubahan pada data aktual yang akan dilakukan. Hanya tag yang akan diformat dan indentasi.
Charles Prakash Dasari
2
Saya perhatikan bahwa itu bekerja dengan baik dengan UTF8, tetapi tidak dengan konten file Unicode XML.
Nayan
1
@SteveWellens, Anda dapat mengakses deklarasi melalui doc.Declaration.ToString() + doc.ToString()atau dengan menggunakan doc.Savealih-alih doc.ToString. Lihat tautan ini untuk lebih jelasnya.
David French
1
Sarankan termasuk ruang nama karena mencegah pengguna harus mencari ruang nama untuk kelas yang mungkin belum pernah mereka gunakan sebelumnya. menggunakan System.Xml.Linq; Bekerja dengan baik, terima kasih!
Scott Moniz
61

Yang ini, dari kristopherjohnson lebih baik:

  1. Itu tidak memerlukan header dokumen XML.
  2. Memiliki pengecualian yang lebih jelas
  3. Menambahkan opsi perilaku tambahan: OmitXmlDeclaration = true, NewLineOnAttributes = true
  4. Lebih sedikit baris kode

    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
sumber
Todd, dapatkah Anda mengklarifikasi apa yang Anda maksud dengan "tidak memerlukan header dokumen XML"? Saya sudah mencoba solusi Charles Prakash Dasari dan baru saja melewati sebuah fragmen XML tanpa deklarasi xml (yaitu tanpa <?xml version="1.0" encoding="UTF-8" ?>garis di atas) dan itu bekerja dengan baik.
Simon Tewsi
3
Dibandingkan dengan jawaban yang diterima. Dibandingkan dengan Charles, yang ini akan memiliki konfigurasi yang lebih baik. Namun saya mungkin akan menggunakan metode Charlies di masa depan sendiri, konfigurasi seperti itu akan menjadi persyaratan yang langka.
Todd
1
Yang ini jauh lebih baik dan lebih pendek
Alex Jolig
8

Solusi sederhana yang bekerja untuk saya:

        XmlDocument xmlDoc = new XmlDocument();
        StringWriter sw = new StringWriter();
        xmlDoc.LoadXml(rawStringXML);
        xmlDoc.Save(sw);
        String formattedXml = sw.ToString();
ZeeProgrammer
sumber
ini membuat file xml dengan <? xml version = "1.0" encoding = "utf-16"?> sebagai header-nya. Ini tidak diuraikan oleh XmlSerializer, dengan kesalahan 'Tidak ada tanda urutan byte Unicode'. Cara mengatasinya adalah menghapus encoding = "utf-16", lihat: stackoverflow.com/questions/29915467/… .
Declan Taylor
6

Periksa tautan berikut: Cara mencetak XML dengan cantik (Sayangnya, tautan itu sekarang mengembalikan 404 :()

Metode dalam tautan menggunakan string XML sebagai argumen dan mengembalikan string XML yang terbentuk dengan baik.

Saya baru saja menyalin kode sampel dari tautan untuk membuat jawaban ini lebih komprehensif dan nyaman.

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
sumber
2
Berfungsi bagus untuk saya, saya hanya membuatnya menjadi metode ekstensi string. Juga situs web itu sedang down, jadi ada baiknya Anda mengambil salinan ...
goodguys_activate
1
Jawaban rangkap. @ SM Kamran memposting jawaban yang sama juga.
Vahid Farahmandian
@VahidFarahmandian Ya. Saya tidak bisa berbuat banyak tentang hal itu karena saya memposting 1 menit lebih awal darinya :) BTW, saya mencoba untuk menambahkan dari mana jawabannya berasal untuk memberikan penghargaan pada poster blog. Sayangnya, tautannya rusak sekarang :(.
Chansik Im
Saya suka jawaban ini yang terbaik dibandingkan dengan yang dari Charles (FormatXml) dan Todd (PrettyXml), karena jawaban ini tidak menghapus <?xml...?>garis. Jawaban ini mendapatkan apa yang semula saya pikirkan. Satu-satunya negatif adalah bahwa saya lebih suka tab daripada ruang yang digunakan secara asli. Saya mengatur Indentation = 1dan IndentChar = '\t'mendapatkan apa yang saya inginkan.
Sarah Weinberger
@ CHICoder007 Terima kasih atas komentar tentang metode ekstensi. Anda mengajari saya sesuatu yang baru. Menambahkan (this String XML)karya hebat.
Sarah Weinberger
4

Saya mencoba:

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

itu berfungsi dengan baik seperti yang diharapkan.

Akhilesh singh
sumber
tapi ini menghilangkan tag <? xml?> di bagian atas
Juran
2

.NET 2.0 mengabaikan pemecahan nama, dan dengan pembuangan sumber daya yang tepat, indentasi, spasi-putih dan pengkodean khusus :

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

Pemakaian:

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
sumber
0

jika Anda memuat XMLDoc saya cukup yakin fungsi .ToString () memiliki kelebihan untuk ini.

Tetapi apakah ini untuk debugging? Alasannya dikirim seperti itu adalah untuk mengambil lebih sedikit ruang (yaitu menghapus spasi yang tidak perlu dari XML).

Tempat menyimpan bahan makanan
sumber
0

Output Pretty XML yang dapat disesuaikan dengan deklarasi XML UTF-8

Definisi kelas berikut memberikan metode sederhana untuk mengonversi string XML input menjadi output XML yang diformat dengan deklarasi xml sebagai UTF-8. Ini mendukung semua opsi konfigurasi yang ditawarkan oleh kelas 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; }
            }
        }
    }
}

Kemungkinan untuk peningkatan lebih lanjut: -

  • Metode tambahan GetPrettyXml(XmlDocument doc, XmlWriterSettings settings)dapat dibuat yang memungkinkan pemanggil untuk menyesuaikan output.
  • Metode tambahan GetPrettyXml(String rawXml)dapat ditambahkan yang mendukung parsing teks mentah, daripada meminta klien menggunakan XmlDocument. Dalam kasus saya, saya perlu memanipulasi XML menggunakan XmlDocument, jadi saya tidak menambahkan ini.

Pemakaian:

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
sumber