Search code examples
c#.netxmldocument

XmlDocument not preserving whitespace


XmlDocument is adding a space at the end of self closing tags, even with PreserveWhitespace set to true.

// This fails
string originalXml = "<sample><node id=\"99\"/></sample>";

// Convert to XML
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(originalXml);

// Save back to a string
string extractedXml = null;

using (MemoryStream stream = new MemoryStream())
{
    doc.Save(stream);

    stream.Position = 0;
    using(StreamReader reader = new StreamReader(stream))
    {
        extractedXml = reader.ReadToEnd();
    }
}

// Confirm that they are identical
Assert.AreEqual(originalXml, extractedXml);

The desired output is:

<sample><node id="99"/></sample>

But I am getting:

<sample><node id="99" /></sample>

Is there a way to suppress that extra space?


Solution

  • Here's how XmlDocument.Save(Stream) looks like :

    public virtual void Save(Stream outStream)
    {
      XmlDOMTextWriter xmlDomTextWriter = new XmlDOMTextWriter(outStream, this.TextEncoding);
      if (!this.preserveWhitespace)
        xmlDomTextWriter.Formatting = Formatting.Indented;
      this.WriteTo((XmlWriter) xmlDomTextWriter);
      xmlDomTextWriter.Flush();
    }
    

    So setting PreserveWhiteSpace has no effect on the inside of the nodes. The documentation of the XmlTextWriter says :

    When writing an empty element, an additional space is added between tag name and the closing tag, for example . This provides compatibility with older browsers.

    So I guess there is no easy way out. Here's a workaround tho:

    So I wrote a wrapper class MtxXmlWriter that is derived from XmlWriter and wraps the original XmlWriter returned by XmlWriter.Create() and does all the necessary tricks.

    Instead of using XmlWriter.Create() you just call one of the MtxXmlWriter.Create() methods, that's all. All other methods are directly handed over to the encapsulated original XmlWriter except for WriteEndElement(). After calling WriteEndElement() of the encapsulated XmlWriter, " />" is replaced with "/>" in the buffer: