Example: Using extension functions from multiple processors

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