Example: Generating multiple output files
page 134 chapter
chapter titleThe Hello World Exampletitle
paraIf this chapter had any text, it would appear here.para chapter
chapter titleXPathtitle
paraIf this chapter had any text, it would appear here.para chapter
chapter titleStylesheet Basicstitle
paraIf this chapter had any text, it would appear here.para chapter
chapter titleBranching and Control Elementstitle
paraIf this chapter had any text, it would appear here.para chapter
chapter titleFunctionstitle
paraIf this chapter had any text, it would appear here.para chapter
chapter titleCreating Links and Cross-Referencestitle
paraIf this chapter had any text, it would appear here.para chapter
chapter titleSorting and Grouping Elementstitle
paraIf this chapter had any text, it would appear here.para chapter
chapter titleCombining XML Documentstitle
paraIf this chapter had any text, it would appear here.para chapter
book
For our first example, we want to create a stylesheet that converts the document to HTML, writing the contents of each
chapter
element to a separate HTML file. Heres what that stylesheet looks like:
?xml version=1.0? xsl:stylesheet version=1.0 xmlns:xsl=http:www.w3.org1999XSLTransform
xmlns:redirect=org.apache.xalan.xslt.extensions.Redirect extension-element-prefixes=redirect
xsl:output method=html xsl:template match=
xsl:choose xsl:when test=element-availableredirect:write
xsl:for-each select=bookchapter redirect:write select=concatchapter, position, .html
html head
titlexsl:value-of select=titletitle head
body h1xsl:value-of select=titleh1
xsl:apply-templates select=para xsl:if test=notposition=1
pa href=chapter{position-1}.htmlPreviousap xsl:if
xsl:if test=notposition=last pa href=chapter{position+1}.htmlNextap
xsl:if body
html redirect:write
xsl:for-each xsl:when
page 135 xsl:otherwise
html head
titlexsl:value-of select=booktitletitle head
xsl:for-each select=bookchapter h1xsl:value-of select=titleh1
xsl:apply-templates select=para xsl:for-each
html xsl:otherwise
xsl:choose xsl:template
xsl:template match=para pxsl:apply-templates select=|textp
xsl:template xsl:stylesheet
Lets go through the relevant parts of this example. To begin with, our
xsl:stylesheet
element defines the
redirect
namespace prefix and tells the XSLT engine that the prefix will be used to refer to an extension element.
xsl:stylesheet version=1.0 xmlns:xsl=http:www.w3.org1999XSLTransform xmlns:redirect=org.apache.xalan.xslt.extensions.Redirect
extension-element-prefixes=redirect
The syntax of everything weve done so far is according to the standard, although theres a fair amount of latitude in what the XSLT engines do with the information weve defined. For
example, when defining the
redirect
namespace, Xalan uses the value here as a Java class name. In other words, Xalan attempts to load the class
org.apache.xalan.xslt. extensions.Redirect
when it encounters an extension element or function defined with this namespace. The way other XSLT processors use the namespace URI can vary.
To this point, weve simply defined our extension class so Xalan can find our code, load it, and invoke it. Our next step is to actually use it:
xsl:when test=element-availableredirect:write xsl:for-each select=bookchapter
redirect:write select=concatchapter, position, .html html
head titlexsl:value-of select=titletitle
head body
h1xsl:value-of select=titleh1 xsl:apply-templates select=para
xsl:if test=notposition=1 pa href=chapter{position-1}.htmlPreviousap
xsl:if xsl:if test=notposition=last
pa href=chapter{position+1}.htmlNextap xsl:if
body html
redirect:write xsl:for-each
xsl:when
page 136
This code does several things:
•
It checks to see if our extension element is available. If it is, well use it; if not, the
xsl:otherwise
element will be evaluated instead.
•
For each
chapter
in our XML document, it calls an extension element from our
Redirect
class. In the example here, were calling the
redirect:write
element, which opens a file and directs all the output generated by Xalan into that file. Notice
that the filename here is generated automatically; the filename for the first
chapter
is chapter1.html, the filename for the second is chapter2.html, etc. This convenient naming convention creates a unique filename for each chapter and makes it easy to
figure out which filename contains the output from each chapter.
•
It creates the HTML tags to define the document and its
title
. After creating the
head
section, it creates an
h1
for the chapter title, followed by a
p
generated from each
para
element in the XML source.
•
It generates hyperlinks between the different documents. If a given document is any chapter other than the first
notposition=1
, it creates a link to the previous chapter. The filename for the previous chapter is generated with the expression
chapter{position-1}.html
. If the document is any chapter other than the last
notposition=last
, it creates a link to the next chapter. The filename for the next chapter is generated with the function call
concatchapter, position+1, .html
. In this example, we used both the curly brace notation and the
xsl:attribute
element. Both work the same way; for the rest of this chapter, well use the curly brace notation to save space. For more information, see the discussion of
Section 3.3 in
Chapter 3 .
•
After any required hyperlinks have been generated, it writes the closing HTML tags and ends the
redirect:write
element. Ending the
redirect:write
element closes the file.
An individual output file looks like Figure 8-1
.
Figure 8-1. An individual output file
This particular chapter contains both a
Previous
and a
Next
link. The first chapter wont have a
Previous
link, and the last chapter wont have a
Next
; other than that, all individual chapters are formatted the same way.
page 137
That code covers how we generate multiple output files when the extension element is available. When it isnt available, we simply generate a single HTML file that contains the
text of all the chapters:
xsl:otherwise html
head titlexsl:value-of select=booktitletitle
head xsl:for-each select=bookchapter
h1xsl:value-of select=titleh1 xsl:apply-templates select=para
xsl:for-each html
xsl:otherwise
In the
xsl:otherwise
element, we create a single HTML element, then process each
chapter
in turn. The output is a single large file; not ideal for a really large document, but an acceptable alternative when our extension element isnt available.
In this relatively simple example, weve broken a single XML document into multiple HTML files, weve generated useful filenames for all of them, and weve automatically built
hyperlinks between the different HTML files. If we add, delete, or move a chapter, we can simply rerun our stylesheet and all the files and links between them will be updated. For now,
weve simply discussed how to use an extension; well talk about how to write your own extension later in this chapter.