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:
<book>
<title>C# in a Nutshell</title>
<authors>
<author>Drayton</author>
<author>Neward</author>
<author>Albahari</author>
</authors>
</book>
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>
<xsl:template match="author">
<i><xsl:value-of select="text( )" /></i>
</xsl:template>
</xsl:transform>
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( );
transform.Load("book2html.xsl");
/* 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>
<xsl:template match="author">
<i><xsl:value-of select="text( )" /></i>
</xsl:template>
</xsl:transform>
*/
// 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>" +
"</book>";
XmlTextReader xtr =
new XmlTextReader(new StringReader(xmlContent));
XmlDocument doc = new XmlDocument( );
doc.Load(xtr);
// Define where the results should go
StringWriter output = new StringWriter( );
// Transform
transform.Transform(doc, null, output);
Console.WriteLine(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.
|