Let's take our basic stylesheet and extend it to allow us to transform the DocBook XML document presented in Example E-8 into HTML.
<?xml version="1.0"?> <book> <title>Camels: An Historical Perspective</title> <chapter> <title>Chapter One</title> <para> It was a dark and <emphasis>stormy</emphasis> night... </para> </chapter> </book>
First we need to alter the root template of our stylesheet:
<xsl:template match="/"> <html> <head><xsl:copy-of select="/book/title"/></head> <body> <xsl:apply-templates/> </body> </html> </xsl:template>
Here we have created the top-level structure of our output document and copied over the book's <title> element into the <head> element of our HTML page. The <xsl:apply-templates/> element tells the XSLT processor to pass on the entire contents of the current element (in this case the <book> element, since it is the root-level element in the source document) for further processing.
Now we need to create template rules for the other elements in the document:
<xsl:template match="chapter"> <div class="chapter"> <xsl:attribute name="id">chapter_id<xsl:number value="position( )" format="A"/></xsl:attribute> <xsl:apply-templates/> </div> </xsl:template> <xsl:template match="para"> <p><xsl:apply-templates/></p> </xsl:template>
Here we see more examples of recursive processing. The <para> and <chapter> elements are transformed into <div> and <p> elements, and the contents of those elements are passed along for further processing. Note also that the XPath expressions used within the template rules are evaluated in the context of the current element being processed. XSLT also maintains what is called the "current node list," which is the list of nodes being processed. In the example above, this is the list of all chapter elements. This is an example of XSLT using "least surprise".
While this sort of recursive processing is extremely powerful, it can also be quite a performance hit[66] and is necessary only for those cases where the current element contains other elements that need to be processed. If we know that a particular element will not contain any other elements, we need to return only that element's text value.
[66]Although, since XSLT engines tend to be written in C, they are still very fast (often faster than most compiled Perl templating solutions).
<xsl:template match="emphasis"> <em><xsl:value-of select="."/></em> </xsl:template> <xsl:template match="chapter/title"> <h2><xsl:value-of select="."/></h2> </xsl:template> <xsl:template match="book/title"> <h1><xsl:value-of select="."/></h1> </xsl:template> </xsl:stylesheet>
Look closely at the last two template elements. Both match a <title> element, but one defines the rule for handling titles whose parent is a book element, while the other handles the chapter titles. In fact, any valid XPath expression, XSLT function call, or combination of the two can be used to define the match rule for a template element.
Finally, we need only save our stylesheet as docbook-snippet.xsl. Once our source document is associated with this stylesheet (see Section E.6 later in this appendix), we can point our browser to camelhistory.xml, and we'll see the output generated by the code in Example E-9.
<?xml version="1.0"?> <html> <head> <title>Camels: An Historical Perspective</title> </head> <body> <h1>Camels: An Historical Perspective</h1> <div class="chapter" id="Chapter One"> <h2>Chapter One</h2> <p> It was a dark and <em>stormy</em> night... </p> </div> </body> </html>
The entire stylesheet is rendered in Example E-10.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <html> <head><xsl:copy-of select="/book/title"/></head> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="chapter"> <div class="chapter"> <xsl:attribute name="id">chapter_id<xsl:number value="position( )" format="A"/></xsl:attribute> <xsl:apply-templates/> </div> </xsl:template> <xsl:template match="para"> <p><xsl:apply-templates/></p> </xsl:template> <xsl:template match="emphasis"> <em><xsl:value-of select="."/></em> </xsl:template> <xsl:template match="chapter/title"> <h2><xsl:value-of select="."/></h2> </xsl:template> <xsl:template match="book/title"> <h1><xsl:value-of select="."/></h1> </xsl:template> </xsl:stylesheet>
 
Continue to: