 | Level: Introductory Jack Herrington (jherr@pobox.com), Editor-in-Chief, Code Generation Network
18 Mar 2005 For any reasonably complex data set, you need multiple views to navigate it. Take a QA test system, for example: With a pool of tests and test results, you need to see the data by date, by test category, by individual test, and so on. Each view would be in its own HTML file. So, can you have a single template in XSLT 2.0 build multiple HTML files from the one input data set?
The first version of XSLT was very strict. It had one input and one output (although you could
have more than one template file). Version 2 of the standard still restricts you to one input, but
the output system is more flexible. Now, you can have multiple output files using the
xsl:result-document directive. This new tag has two key attributes,
as shown in Table 1.
Table 1. xsl:result-document attributes
|
Attribute
|
Description
|
href
| The file name or fully qualified URL of the output file |
format
| The name of the format to use as defined in a corresponding xsl:output directive |
To test this directive, I have one input XML file that includes a set of test results (see Listing 1).
Listing 1. The input XML file
<?xml version="1.0" encoding="UTF-8"?>
<tests>
<testrun run="test1">
<test name="foo" pass="true" />
<test name="bar" pass="true" />
<test name="baz" pass="true" />
</testrun>
<testrun run="test2">
<test name="foo" pass="true" />
<test name="bar" pass="false" />
<test name="baz" pass="false" />
</testrun>
<testrun run="test3">
<test name="foo" pass="false" />
<test name="bar" pass="true" />
<test name="baz" pass="false" />
</testrun>
</tests>
|
This is pretty simple stuff. Within each test run is a set of
named tests with the pass flag, which tells you whether the test was successful.
Create a file for each test
The first thing I need to do is create a file for each test result. Listing 2 shows the XSL template.
Listing 2. Code to create a file for each test
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:output method="html" indent="yes" name="html"/>
<xsl:template match="/">
<xsl:for-each select="//testrun">
<xsl:variable name="filename"
select="concat('output1/',@run,'.html')" />
<xsl:value-of select="$filename" /> <!-- Creating -->
<xsl:result-document href="{$filename}" format="html">
<html><body>
<xsl:value-of select="@run"/>
</body></html>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
|
A few things are worth noting, starting right at the top of the file. The version
attribute on the stylesheet tag is set to 2.0 so that you can use the
xsl:result-document tag. After that, you see that the stylesheet itself
is set to text as the output type. This means that if I want the HTML
files to have HTML formatting, I need to define a second named format of type
html.
I use this format in the xsl:result-document tag.
From there, I use an xsl:for-each loop to iterate through the
testrun tags. Within each of those tags, I use the variable
tag to create a new $filename variable that concatenates the output
directory name (output1), the name of the run, and the .html file extension into a single path.
With that in hand, I tell the user what files I'm creating by using the value-of
tag with my $filename variable. Then, I open the new document with
the xsl:result-document tag and output the HTML. Listing 3 shows
the output of the engine when it's run on the sample data file.
Listing 3. The output of Saxon when run on the sample data file
Creating output1/test1.html
Creating output1/test2.html
Creating output1/test3.html
|
Get better output
It seems somehow counterintuitive that the contents of the xsl:result-document
tag are evaluated in the same way as the rest of the template, but they are. And all the
variables within the template context are available.
To demonstrate this, I've upgraded the code within the xsl:result-document
tag to provide more information about the results of the test (see Listing 4).
Listing 4. Better HTML output from the template
<xsl:result-document href="{$filename}" format="html">
<html><head>
<title>Test results - <xsl:value-of select="@run"/></title>
</head><body>
<xsl:value-of select="@run"/> <!-- Run -->
<table>
<tr><td>Test</td><td>Pass</td></tr>
<xsl:for-each select="test">
<tr><td>
<xsl:value-of select="@name" />
</td><td>
<xsl:value-of select="@pass" />
</td></tr>
</xsl:for-each>
</table>
</body></html>
</xsl:result-document>
|
See Listing 5 for the HTML result of this output.
Listing 5. The upgraded HTML output
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<title>Test results - test1</title>
</head>
<body>
<!-- Run: test1-->
<table>
<tr>
<td>Test</td>
<td>Pass</td>
</tr>
<tr>
<td>foo</td>
<td>true</td>
</tr>
<tr>
<td>bar</td>
<td>true</td>
</tr>
<tr>
<td>baz</td>
<td>true</td>
</tr>
</table>
</body>
</html>
|
Create an index
To finish, I need to add an index file that points to all the output test results. To do that, I
use another xsl:result-document tag and hard-code the output
to go to an index file (see Listing 6).
Listing 6. Code to build the index file
<!-- Creating the index -->
<xsl:result-document href="output3/index.html"
format="html">
<html><head><title>Test Index</title></head>
<body>
<xsl:for-each select="//testrun">
<a href="{@run}.html"><xsl:value-of select="@run" />
</a><br/>
</xsl:for-each>
</body>
</html>
</xsl:result-document>
|
This section goes right after the xsl:for-each loop that builds
the HTML files for each test case. Listing 7 shows the index file for the example data set.
Listing 7. The index file
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<title>Test Index</title>
</head>
<body><a href="test1.html">test1</a><br>
<a href="test2.html">test2</a><br>
<a href="test3.html">test3</a><br></body>
</html>
|
Summary
Using the xsl:result-document directive, you can have a single XSL
template output to multiple files from a single data source. This functionality, which was a nonstandard
extension in XSLT 1.x, opens a world of opportunity for XSLT template authors.
Resources
About the author
Rate this page
|  |