Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save XDocument with indentation and xml:space="preserve"

Tags:

c#

.net

xml

I want to pretty print an XDocument but leaving white space inside xml:space="preserve" elements untouched.

This snippet:

new XDocument(
    new XElement("a",
        new XElement("b",
            new XElement("c"))))
    .Save(Console.Out);

Results in the following indented output (which is just want I want):

<a>
  <b>
    <c />
  </b>
</a>

However, let's say that I need to preserve white space inside the <b> element:

new XDocument(
    new XElement("a",
        new XElement("b",
            new XAttribute(XNamespace.Xml + "space", "preserve"),
            new XElement("c"))))
    .Save(Console.Out);

In this case I get the following output:

<a>
  <b xml:space="preserve">
    <c />
  </b>
</a>

This is not good, since indentation was added inside the xml:space="preserve" scope. The expected output in this case would be:

<a>
  <b xml:space="preserve"><c /></b>
</a>

I'm surprised that XDocument doesn't support this by default.

Is it possible to get a pretty printed (indented) output from an XDocument and keeping white space inside xml:space="preserve" as-is?

I understand that one option is to write my own XmlWriter implementation that takes care of this, but I would rather use something from the framework (if available).

like image 639
Mårten Wikström Avatar asked Oct 18 '22 07:10

Mårten Wikström


1 Answers

It seems there is a bug in XmlWriter, as described in this self-answered question. The bug is: XmlWriter will respect space:preserve tag unless there are no whitespace inside tag marked with this attribute. If there are no whitespace - it can (for some reason) add some. Because internally XDocument also uses XmlWriter - it shows the same behavior. And indeed if you add 0-length whitespace by hand, like this:

new XDocument(
    new XElement("a",
        new XElement("b",
           new XAttribute(XNamespace.Xml + "space", "preserve"),
              new XText(""),
              new XElement("c"))))
.Save(Console.Out);

it will respect whitespace preserve tag and produce expected output.

like image 124
Evk Avatar answered Nov 03 '22 20:11

Evk