A typical course of action when converting XML into HTML is to make
two or more passes over the XML to create menu or index pages and
content pages. The menu pages contain links to the content pages. The
following solution generates an
index and summary
pages for SalesBySalesPerson.xml
(see Chapter 2):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://icl.com/saxon" extension-element-prefixes="saxon"> <xsl:output method="html"/> <xsl:template match="/"> <xsl:apply-templates select="*" mode="index"/> <xsl:apply-templates select="*" mode="content"/> </xsl:template> <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = --> <!-- Create index.html (mode = "index") --> <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = --> <xsl:template match="salesBySalesperson" mode="index"> <saxon:output href="EB0596003722_2.html"> <html> <head> <title>Sales By Salesperson Index</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <h1>Sales By Salesperson</h1> <xsl:apply-templates mode="index"/> </body> </html> </saxon:output> </xsl:template> <xsl:template match="salesperson" mode="index"> <h2> <a href="{concat(@name,'.html')}"> <xsl:value-of select="@name"/> </a> </h2> </xsl:template> <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = --> <!-- Create @name.html (mode = "content") --> <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = --> <xsl:template match="salesperson" mode="content"> <saxon:output href="{@name}.html"> <html> <head> <title><xsl:value-of select="@name"/> Sales</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <h1><xsl:value-of select="@name"/> Sales</h1> <ol> <xsl:apply-templates mode="content"/> </ol> </body> </html> </saxon:output> </xsl:template> <xsl:template match="product" mode="content"> <li><xsl:value-of select="@sku"/>      $<xsl:value- of select="@totalSales"/></li> </xsl:template> </xsl:stylesheet>
Notice how the modes separate the transformation of XML elements into index content versus the information content of each salesperson’s HTML page. Modes are used commonly in HTML transformations because they allow data to be mapped onto presentation in multiple ways within a single stylesheet.
As designed, this stylesheet is limited to batch processing. You can
parameterize it to control which document gets created. This
parameter also removes the need for the nonstandard
saxon:output
extension:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <!—Used to specify which document to output—> <!—INDEX : creates the index document —> <!—Sales Person's name : creates the page for that salesperson —> <xsl:param name="which" select="'INDEX'"/> <xsl:template match="/"> <xsl:choose> <xsl:when test="$which='INDEX'"> <xsl:apply-templates select="*" mode="index"/> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="*/salesperson[@name = $which]" mode="content"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = --> <!-- Create index.html (mode = "index") --> <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = --> <xsl:template match="salesBySalesperson" mode="index"> <!— Removed saxon:output. The rest is the same. —> </xsl:template> <!-- ... --> <xsl:template match="salesperson" mode="content"> <!— Removed saxon:output. The rest is the same. —> </xsl:template> <!-- ... --> </xsl:stylesheet>
This technique would be slightly more robust if each salesperson used an ID rather than her name as the parameter.
The solution does not create fancy content, but it does illustrate
the basic mechanics of producing linked HTML content. To produce all
web pages with a single stylesheet, you were forced to use a
nonstandard XSLT 1.0 element (saxon:output
).
Similar extensions are available in most processors.
The stylesheet produces relative links, which is what you want most of the time. However, when you need absolute links, rather than hardcoding a URL, you might consider incorporating a top-level parameter that can be set to the URL:
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:param name="URL" select="http://www.mycompany.com/"/>
<!-- elided ... -->
<xsl:template match="salesperson" mode="index">
<h2>
<a href="{$URL}{@name}.html'">
<xsl:value-of select="@name"/>
</a>
</h2>
</xsl:template>
See Recipe 6.6 for more information on producing multiple output documents.
The content produced by these transformations is not very user friendly. Recipe 8.3 and Recipe 8.4 show how to improve the result’s aesthetics.