222

I have an XML string as such:

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

There are no lines between one element and another, and thus is very difficult to read. I want a function that formats the above string:

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

Without resorting to manually write the format function myself, is there any .Net library or code snippet that I can use offhand?

Graviton
  • 81,782
  • 146
  • 424
  • 602
  • 1
    props to CMS, question is a duplicate http://stackoverflow.com/questions/203528 – Spence Jul 14 '09 at 06:24
  • 2
    Not a duplicate. That one specifies `XmlDocument` which would disqualify the highest voted answer on this question. – sirdank Oct 02 '17 at 15:52

12 Answers12

370

You will have to parse the content somehow ... I find using LINQ the most easy way to do it. Again, it all depends on your exact scenario. Here's a working example using LINQ to format an input XML string.

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 statements are ommitted for brevity]

Charles Prakash Dasari
  • 4,964
  • 1
  • 27
  • 46
  • Is this going to affect strictly line-breaks and indentation? I do not want any other changes, like "0" being changed to "0.0" etc. When all whitespace is stripped, I want the stripped result-string be exactly the same as the stripped input-string. – Radim Cernej Feb 12 '15 at 21:11
  • 3
    @radim Yes. No changes to the actual data will be done. Only tags will be formatted and indented. – Charles Prakash Dasari Feb 13 '15 at 23:44
  • Great, thank you. I have added this snippet to my code, it works well. – Radim Cernej Feb 14 '15 at 02:27
  • 2
    I've noticed that it worked well with UTF8, but not with Unicode XML file contents. – Nayan Jan 20 '16 at 07:10
  • 1
    @SteveWellens, you can access the declaration via `doc.Declaration.ToString() + doc.ToString()` or by using `doc.Save` instead of `doc.ToString`. See [this link](http://smsohan.com/blog/2008/08/12/xdocumenttostringwithxmldeclaration-get/) for more details. – chinookf Mar 01 '19 at 18:09
  • 3
    Suggest including the namespaces as it prevents users from having to go look up a namespace for a class they may not have used a lot before. using System.Xml.Linq; Works well Thanks! – Scott Moniz May 21 '19 at 21:05
  • When i try this, the xml-declaration of my source xml text is no more there! I just want formatting, not changing anything regarding the content. – brighty Jun 29 '23 at 21:45
210

Use 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;
}
Bakudan
  • 19,134
  • 9
  • 53
  • 73
S M Kamran
  • 4,423
  • 7
  • 25
  • 35
  • 8
    This works if you're dealing with code that is on an old version of the .NET framework pre-LINQ, but the other example is a lot cleaner. – Mike Jan 10 '13 at 22:33
  • 9
    To clarify Mike's comment: LINQ was introduced in .NET 3.5. So if you're using a version of .NET older than that (.NET 1, 1.1, 2 or 3.0) then you'll have to use this answer. But if you're using .NET 3.5 or later Charles Prakash Dasari's answer is a lot simpler. – Simon Elms Sep 04 '13 at 23:54
  • 1
    @SM Kamran i am using your code but i getting error look like {"Cannot access a closed Stream."} on writer.Close(); pls give solution. – Jatin Gadhiya Aug 07 '14 at 11:22
  • @JatinGadhiya I had the same problem and I resolved it by using {using block} in defining the streams. in such way you do not need to close the stream manually and streams will be closed automatically when reaching the end of the using block . – Vahid Farahmandian Apr 13 '16 at 12:25
66

This one, from kristopherjohnson is heaps better:

  1. It doesn't require an XML document header either.
  2. Has clearer exceptions
  3. Adds extra behaviour options: OmitXmlDeclaration = true, NewLineOnAttributes = true
  4. Less lines of code

    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();
    }
    
Kind Contributor
  • 17,547
  • 6
  • 53
  • 70
  • Todd, could you clarify what you mean by "doesn't require an XML document header"? I've tried Charles Prakash Dasari's solution and just passed in an XML fragment without an xml declaration (ie without the `` line at the top) and it worked fine. – Simon Elms Sep 05 '13 at 21:10
  • 3
    Compared to the accepted answer. Compared to Charles, this one would have better configurability. However I would probably use Charlies method in the future myself, such configurability would be a rare requirement. – Kind Contributor Oct 21 '13 at 05:21
  • 1
    This one is much much better and shorter – Ghasem Apr 08 '15 at 03:56
  • This deletes my xml declaration. – brighty Jun 29 '23 at 21:56
14

The simple solution that is working for me:

        XmlDocument xmlDoc = new XmlDocument();
        StringWriter sw = new StringWriter();
        xmlDoc.LoadXml(rawStringXML);
        xmlDoc.Save(sw);
        String formattedXml = sw.ToString();
ZeeProgrammer
  • 195
  • 1
  • 13
  • 1
    this creates an xml file with as its header. This was not parsed by XmlSerializer, with the error 'There is no Unicode byte order mark'. The fix was to remove the encoding="utf-16", see: https://stackoverflow.com/questions/29915467/there-is-no-unicode-byte-order-mark-cannot-switch-to-unicode/29918434. – Declan Taylor Mar 18 '20 at 12:51
9

Check the following link: How to pretty-print XML (Unfortunately, the link now returns 404 :()

The method in the link takes an XML string as an argument and returns a well-formed (indented) XML string.

I just copied the sample code from the link to make this answer more comprehensive and convenient.

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
  • 1,473
  • 8
  • 13
  • 2
    Works great for me, I just made it an extension method of string. Also that website is down, so it's good you snagged a copy... – makerofthings7 Jan 20 '11 at 21:03
  • 1
    Duplicate answer. @S M Kamran posts the same answer too. – Vahid Farahmandian Apr 13 '16 at 11:59
  • @VahidFarahmandian Yes. I couldn't do much about it because I posted 1 minute earlier than him :) BTW, I was trying to add where the answer came from to give the credit to the blog poster. Unfortunately, the link is broken now :(. – Chansik Im Apr 13 '16 at 18:08
  • I like this answer the best compared to the one from Charles (FormatXml) and Todd (PrettyXml), because this answer does not strip out the `` line. This answer gets what I originally had in mind. The only negative would be that I would prefer tabs rather than spaces used natively. I set `Indentation = 1` and `IndentChar = '\t'` to get exactly what I wanted. – Sarah Weinberger Aug 07 '18 at 19:59
  • @CHICoder007 Thank you for the comment about extension method. You taught me something new. Adding in a `(this String XML)` works great. – Sarah Weinberger Aug 07 '18 at 20:35
5

I tried:

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

it is working fine as expected.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
3

.NET 2.0 ignoring name resolving, and with proper resource-disposal, indentation, preserve-whitespace and custom encoding:

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

Usage:

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
  • 78,642
  • 66
  • 377
  • 442
2

It is possible to pretty-print an XML string via a streaming transformation with XmlWriter.WriteNode(XmlReader, true). This method

copies everything from the reader to the writer and moves the reader to the start of the next sibling.

Define the following extension methods:

public static class XmlExtensions
{
    public static string FormatXml(this string xml, bool indent = true, bool newLineOnAttributes = false, string indentChars = "  ", ConformanceLevel conformanceLevel = ConformanceLevel.Document) => 
        xml.FormatXml( new XmlWriterSettings { Indent = indent, NewLineOnAttributes = newLineOnAttributes, IndentChars = indentChars, ConformanceLevel = conformanceLevel });

    public static string FormatXml(this string xml, XmlWriterSettings settings)
    {
        using (var textReader = new StringReader(xml))
        using (var xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { ConformanceLevel = settings.ConformanceLevel } ))
        using (var textWriter = new StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                xmlWriter.WriteNode(xmlReader, true);
            return textWriter.ToString();
        }
    }
}

And now you will be able to do:

var inXml = @"<?xml version='1.0'?><response><error code='1'> Success</error></response>";
var newXml = inXml.FormatXml(indentChars : "", newLineOnAttributes : false); // Or true, if you prefer
Console.WriteLine(newXml);

Which prints

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

Notes:

  • Other answers load the XML into some Document Object Model such as XmlDocument or XDocument/XElement, then re-serialize the DOM with indentation enabled.

    This streaming solution completely avoids the added memory overhead of a DOM.

  • In your question you do not add any indentation for the nested <error code='1'> Success</error> node, so I set indentChars : "". Generally an indentation of two spaces per level of nesting is customary.

  • Attribute delimiters will be unconditionally transformed to double-quotes if currently single-quotes. (I believe this is true of other answers as well.)

  • Passing conformanceLevel : ConformanceLevel.Fragment allows strings containing sequences of XML fragments to be formatted.

  • Other than ConformanceLevel.Fragment, the input XML string must be well-formed. If it is not, XmlReader will throw an exception.

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • 1
    This answer is perfect. Just a note that the nested `using` for `XmlWriter.Create` is important to ensure the XML writer is flushed! I incorrectly converted all the `using` statements to `using` declarations, and it did not work correctly until I added `xmlWriter.Flush();` before the `ToString`. – Singularity Dec 08 '22 at 07:43
1

Customizable Pretty XML output with UTF-8 XML declaration

The following class definition gives a simple method to convert an input XML string into formatted output XML with the xml declaration as UTF-8. It supports all the configuration options that the XmlWriterSettings class offers.

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

Possibilities for further improvement:-

  • An additional method GetPrettyXml(XmlDocument doc, XmlWriterSettings settings) could be created that allows the caller to customize the output.
  • An additional method GetPrettyXml(String rawXml) could be added that supports parsing raw text, rather than have the client use the XmlDocument. In my case, I needed to manipulate the XML using the XmlDocument, hence I didn't add this.

Usage:

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
  • 15,147
  • 6
  • 86
  • 135
1

Check the following link: Format an XML file so it looks nice in C#

// Format the XML text.
StringWriter string_writer = new StringWriter();
XmlTextWriter xml_text_writer = new XmlTextWriter(string_writer);
xml_text_writer.Formatting = Formatting.Indented;
xml_document.WriteTo(xml_text_writer);

// Display the result.
txtResult.Text = string_writer.ToString();
0

if you load up the XMLDoc I'm pretty sure the .ToString() function posses an overload for this.

But is this for debugging? The reason that it is sent like that is to take up less space (i.e stripping unneccessary whitespace from the XML).

Spence
  • 28,526
  • 15
  • 68
  • 103
0

Hi why don't you just try this:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = false;
....
....
xmlDoc.Save(fileName);

PreserveWhitespace = false; that option can be used xml beautifier as well.

Sadikerd
  • 1
  • 1
  • Please provide additional details in your answer. As it's currently written, it's hard to understand your solution. – Community Sep 07 '21 at 13:21