8.4 Transforming a Document Using XSLT

A frequent usage of XPath is to find nodes for extraction and possible transformation into other XML documents, or into non-XML data, such as HTML or flat-file format for legacy consumption. While XPath provides a powerful API for selecting nodes from within an Infoset, writing the procedural code to execute query after query, along with the code to execute against each query result, is tedious and error-prone. Again, the W3C has anticipated this need and provided another XML-based standard, the XSL: Transformations specification (in which XSL originally stood for "eXtensible Stylesheet Language:"), for doing precisely this.

In the following example, we continue to use this XML book as our source data:

  <title>C# in a Nutshell</title>

Suppose you wish to transform this source XML into a format more suitable for end-user consumption, such as HTML. For purely pedagogical reasons, we wish the title to display in bold font in an H1-style heading, with the authors' names displayed in order in italic text.

Certainly, you could write the necessary C# code to execute two XPath queries, one to retrieve the title of the book (/book/title/text( )) and another to retrieve the list of authors for the book (/book/authors/author/text( )). You could then take each resulting XmlNodeList, walk through the results, and echo the HTML back to the caller. However, it is much simpler to write a single file that describes these transformation rules without having to worry about how the work gets done:

<xsl:transform xmlns:xsl="">
  <xsl:template match="title">
    <h1><xsl:value-of select="text( )" /></h1>
  <xsl:template match="author">
    <i><xsl:value-of select="text( )" /></i>

When this transform is run through an XSLT engine, the engine starts at the root node of the source XML (our book element, in this case), and begins to evaluate each <xsl:template> rule specified. Here, the <xsl:template> tags specify a criteria (i.e., an XPath set of nodes) that indicate when this template should be invoked. If a match occurs (such as the case when the current node is the book/title node against the first template in the XSLT), the body of the <xsl:template> tag is fired. Literal text, such as the <h1> and </h1> text, is copied directly to the XSLT engine's output stream; other XSLT tags are in turn evaluated. The <xsl:value-of> tag also specifies an XPath query, but takes the resulting nodes and echoes their "values" (the text in the case of a text( ) node) to the XSLT engine's output stream. Thus, running an XSLT engine using the books that XML input and the XSLT transformation described earlier produces the following:

<h1>C# In A Nutshell</h1><i>Drayton</i><i>Neward</i><i>Albahari</i>

This is, of course, browseable HTML.

The .NET Framework Class Library support for XML includes the programmatic execution of XSLT, using the System.Xml.Xsl.XslTransform class:

using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
class App
  public static void Main(string[ ] args)
    // Load the transform int the XSLT Engine
    XslTransform transform = new XslTransform( );
    /* book2html.xsl contains this code:
      <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          <xsl:template match="title">
            <h1><xsl:value-of select="text( )" /></h1>
          <xsl:template match="author">
            <i><xsl:value-of select="text( )" /></i>
    // Obtain the data to transform
    string xmlContent =
      "<book>" +
      "  <title>C# in a Nutshell</title>" +
      "  <authors>" +
      "    <author>Drayton</author>" +
      "    <author>Neward</author>" +
      "    <author>Albahari</author>" +
      "  </authors>" +
    XmlTextReader xtr = 
      new XmlTextReader(new StringReader(xmlContent));
    XmlDocument doc = new XmlDocument( );
    // Define where the results should go
    StringWriter output = new StringWriter( );
    // Transform
    transform.Transform(doc, null, output);

This XSLT Engine is quite powerful; the middle argument to the XslTransform object allows the .NET programmer to pass in an argument list, which is a collection of parameters from outside the engine to inside the engine, including callback methods that the XSLT Engine can invoke (using Microsoft-specific extensions) when a particular rule is evaluated. See the System.Xsl.Xsl namespace for more details on .NET's support for XSLT. See XSLT, by Doug Tidwell (O'Reilly) for more general information on XSLT.

    Part II: Programming with the .NET Framework
    Part IV: API Quick Reference