27

This has got to be such a simple question but I just can't get the answer.

I have an XmlNode and all I want to do is output this node, as a string, with indentations (tabs or spaces) intact to provide better readability.

So far I tried XmlWriter, XmlTextWriter, XmlDocument, XmlReader.

  • I tried the PreserveWhitespace in XmlDocument but I couldn't get the XmlDocument to output my node.
  • I tried the Formatting = Formatting.Indented property in XmlTextWriter but I couldn't figure out how to output the contents to string.

To output the XmlNode as string WITHOUT indentation is easy. I just do XmlNode.OuterXml. How do I get the indentations in there?

I want to do this without looping through the XmlNode and using brute force to add whitespace, because I think there should be a simpler way.

Thanks.

Edit: For future readers, here is the answer:

  var xmlNode = is some object of type XmlNode

  using (var sw = new StringWriter())
  {
      using (var xw = new XmlTextWriter(sw))
      {
        xw.Formatting = Formatting.Indented;
        xw.Indentation = 2; //default is 1. I used 2 to make the indents larger.

        xmlNode.WriteTo(xw);
      }
      return sw.ToString(); //The node, as a string, with indents!
  }

The reason I needed to do this was output the node's xml with syntax highlighting. I used AvalonEdit to highlight the xml, outputted the highlighted text to html, then converted the html to a FlowDocument which could be displayed in a RichTextBox.

Yuf
  • 610
  • 2
  • 6
  • 14

2 Answers2

34

You were on the right path with the XMLTextWriter, you simply need to use a StringWriter as the base stream. Here are a few good answers on how this is accomplished. Pay particular attention to the second answer, if your encoding needs to be UTF-8.

Edit:

If you need to do this in multiple places, it is trivial to write an extension method to overload a ToString() on XmlNode:

public static class MyExtensions
{
    public static string ToString(this System.Xml.XmlNode node, int indentation)
    {
        using (var sw = new System.IO.StringWriter())
        {
            using (var xw = new System.Xml.XmlTextWriter(sw))
            {
                xw.Formatting = System.Xml.Formatting.Indented;
                xw.Indentation = indentation;
                node.WriteContentTo(xw);
            }
            return sw.ToString();
        }
    }
}
Community
  • 1
  • 1
drharris
  • 11,194
  • 5
  • 43
  • 56
  • thanks for the link! It works. I think I was just searching for the wrong things. I was still stuck on trying to get the node to output even though what I really needed was to get the writer to output to string. Thanks I will update my question with the answer. – Yuf Jun 22 '11 at 15:29
  • Yes, it's one of the pitfalls of OOP that you sometimes have to wrap objects inside other objects to gain functionality. Thankfully, C# gives us many ways to bring some functional programming into the mix, including extension methods. If you find yourself needing to do this a lot, consider making an extension method like the one in my updated answer. – drharris Jun 22 '11 at 16:01
  • This didn't work for me - unless I called it something other than ToString() (like ToIndentedString()) the standard object.ToString() was called instead. – Dave Mar 05 '14 at 18:24
  • @Dave, this should work as long as you're passing in an integer parameter to the `ToString()` method. If you're calling it without parameters, it will default to the original method. This is an overload, not an override. – drharris Mar 14 '14 at 19:26
4

If you don't care about memory or performance, the simplest thing is:

    XElement.Parse(xmlNode.OuterXml).ToString()
Kirill Osenkov
  • 8,786
  • 2
  • 33
  • 37
  • Nice and elegant, especially for scripting, e. g. using PowerShell 7+: `[System.Xml.Linq.XElement]::Parse($xmlNode.OuterXml).ToString()` – zett42 Mar 29 '22 at 14:23