page 138 xt:document
xsl:for-each xsl:when
xsl:when test=containssystem-propertyxsl:vendor, Apache 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 xsl:when test=containssystem-propertyxsl:vendor, SAXON
xsl:for-each select=bookchapter saxon:output href=chapter{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 saxon:output
xsl:for-each xsl:when
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
page 139
All weve done here is add more
xsl:when
elements, each of which tries to figure out which XSLT processor were using. The difference here is that the XT processor doesnt implement
the
element-available
function, so we cant use it in any stylesheet that will be processed by XT. To get around this problem, we use the
system-property
function to get the
vendor
property. If the vendor contains the string James Clark, we know that were using XT. We test the other processors similarly. If we find that were using an XSLT processor we
recognize, we use its extension functions to split the output into multiple HTML files; otherwise, we write all the output to a single file.
Obviously, maintenance of this stylesheet is more involved, but it does give us the freedom to switch XSLT processors. The other downside is that we depend on the value of the
vendor
system property; if the next release of Saxon identifies the vendor as
Saxon
instead of
SAXON
, our stylesheet wont work properly.
8.1.2 Extension Functions
As you might guess, an extension function is defined in a piece of code external to the XSLT processor. You can pass values to the function, and the function can return a result. That
result can be any of the datatypes supported by XPath. In addition, various XSLT processors are free to allow extension functions to return other datatypes, although those other datatypes
must be handled by some other function that does return one of XPaths datatypes.
8.1.2.1 Example: A library of trigonometric functions
As we outlined the functions and operators available in XPath and XSLT, you probably noticed that the mathematical functions at your disposal are rather limited. In this example,
well write an extension that provides a variety of trignometric functions.
Our scenario here is that we want to generate a Scalable Vector Graphics SVG pie chart from an XML document. Our XML document contains the sales figures for various regions
of a company; we need to calculate the dimensions of the various slices of the pie graph for our SVG document. Heres the XML source well be working with:
?xml version=1.0 ? sales
caption heading3Q 2001 Sales Figuresheading
subheading millionssubheading caption
region nameSoutheastname
product name=Heron38.3product product name=Kingfisher12.7product
product name=Pelican6.1product product name=Sandpiper29.9product
product name=Crane57.2product region
region nameNortheastname
product name=Heron49.7product product name=Kingfisher2.8product
product name=Pelican4.8product product name=Sandpiper31.5product
product name=Crane60.0product region
region nameSouthwestname
product name=Heron31.1product product name=Kingfisher9.8product
product name=Pelican8.7product
page 140 product name=Sandpiper34.3product
product name=Crane50.4product region
region nameMidwestname
product name=Heron44.5product product name=Kingfisher9.3product
product name=Pelican5.7product product name=Sandpiper28.8product
product name=Crane54.6product region
region nameNorthwestname
product name=Heron36.6product product name=Kingfisher5.4product
product name=Pelican9.1product product name=Sandpiper39.1product
product name=Crane58.2product region
sales
Our goal is to create an SVG file that looks like that in Figure 8-2
.
Figure 8-2. Target SVG file format
To make things really interesting, well generate an HTML page that embeds the SVG file. Well use the
Redirect
extension we used earlier to generate an HTML file and an SVG file in a single transformation. If we view the HTML page in a web browser, we can use Adobes
SVG plug-in to make the graphic interactive. If we move the mouse over a given slice of the pie, the legend will change to show the sales details for that region of the company. Thus,
well also have to create all the different legends and generate the JavaScript code to make the various SVG elements visible or hidden in response to mouse events.
Figure 8-3 shows how
the graphic looks if we move the mouse over the pie slice for the Southwest region.
Figure 8-3. SVG chart changes in response to mouse events