What the heck is OutputSettings

Oleg Tkachenko over at Signs in the Sand had a recent blog post about the OutputSettings property of XslCompiledTransform.  He posted this example usage:

using (XmlReader src = XmlReader.Create("../../source.xml"))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("../../style.xslt");
XmlWriter result = XmlWriter.Create(Console.Out, xslt.OutputSettings);
xslt.Transform(src, null, result, new XmlUrlResolver());
}

We have also received some feedback that this was somewhat confusing, so I figured I would explain a little bit more about what this 'OutputSettings' property is and why it exists.
When we first thought about creating the XslCompiledTransform class, we figured that we would use an XmlWriter to render the output of the transform.  This made sense for a few reasons:

  • It provided for a good separation of responsibilities (disaggregation)
  • This separation follows the intent of the xslt design committee to separate serialization from transformation
  • It allowed users to pass in their own XmlWriter if they wanted more control over the results of the transform or what happened to those results

All of this was a great benefit to us in developing the transform engine, but, we ran into one sticky issue (well, one we care about for the purposes of this post, anyhow). The problem was that an xsl transform provides some ways within the xslt language to control how the results are written out.  This meant that there were two ways to specify these output options, one in the xslt and one in the WriterSettings passed into an XmlWriter. 
For example, if you write the following stylesheet:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/">
<hello/>
</xsl:template>
</xsl:stylesheet>

You would expect to have your output formatted without indenting because you have specified indent="no".  Of course, as you can imagine, indented formatting of xml also happens to be useful for cases where you are using an XmlWriter without any xslt involved.  For this reason, you will find that the XmlWriterSettings class also has an Indent property.  So, what would you expect to be the result from using the above xslt with the following code?

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create("out.xml", settings);
transform.Transform("test.xml", null, writer);

You will get the indenting specified in the WriterSettings (indent=true) rather then what is specified in the xslt (indent="no").  Of course, it is neither practical nor desirable to have the user specify the correct settings for each of their stylesheets, so instead the XslCompiledTransform exposes the OutputSettings property.  When you call the Load method of the transform, it determines what the correct XmlWriterSettings should look like. In the case that you call one of the Transform() overloads which does not take an XmlWriter, this settings instance will be used to construct a writer on your behalf, but if you are passing in your own writer, then you can either use this instance directly (as you can see above from Oleg's code) or you can Clone() this instance and twiddle whatever particular settings you care about before constructing a writer.