Example: Writing extensions in other languages

page 153 We still need the Redirect class, so that prefix is still with us. The other two prefixes are jython-extension , associated with the URL of the Jython home page though the value could be anything, and lxslt . Xalan uses this prefix to implement scripting languages. Our next step is to actually write the Jython code. With Xalan, this code goes inside an lxslt:component element: lxslt:component prefix=jython-extension functions=cos sin toRadians lxslt:script lang=jpython import math def cosd: return math.cosd def sind: return math.sind def toRadiansd: return d 180 math.pi lxslt:script lxslt:component The prefix attribute associates this lxslt:component with the jython-extension prefix, and the functions attribute lists all of the functions supported by this script. The lxslt:script lang=jpython tells Xalan to use the Jython interpreter the current version of BSF requires us to use lang= jpython , the languages former name whenever these functions are invoked. Now that weve set everything up, all we have to do is invoke the extension functions: xsl:variable name=currentAngle select=jython-extension:toRadiansregionSales div totalSales 360.0 Other than the jython-extension extension before the function call, the rest of our stylesheet is exactly the same. Notice that the Python math library does not define a toRadians function, so we had to define that function ourselves. The other two functions are part of the library, so all we had to do was invoke them. One final point: when we invoke these extension functions written in other languages, the Java CLASSPATH must be set up correctly. If the class libraries for Jython or Javascript or whatever scripting language youre using cant be found, the extension functions will fail. Our example here uses jython.jar, available at http:www.jython.org . We promised wed look at extensions in JavaScript, as well. Heres how the lxslt:component element looks when we write the extension functions in JavaScript: lxslt:component prefix=javascript-extension functions=cos sin toRadians lxslt:script lang=javascript function cosd { return Math.cosd; } function sind { return Math.sind; } function toRadiansd { return d Math.PI 180; } lxslt:script lxslt:component page 154 Here is the lxslt:component element with the extension functions written in Jacl: lxslt:component prefix=jacl-extension functions=cosine sine toRadians lxslt:script lang=jacl proc cosine {d} {expr cosd} proc sine {d} {expr sind} proc toRadians {d} {expr d 3.1415926535897932384626433832795 180.0} lxslt:script lxslt:component Again, most of our task is to use existing features of the language. In the JavaScript and Jacl code, the cos and sin functions are part of the language, and we wrote our own versions of the toRadians function. Jacl doesnt define a constant for pi , so we hardcoded the first 32 digits into the Jacl version of toRadians .

8.1.3 Fallback Processing

If the code that implements a given extension element cant be found, we need some relatively graceful way for the stylesheet to handle the situation. XSLT defines the xsl:fallback element to handle this case. In an earlier stylesheet, we used the element- available function to determine whether a given function is available. In this case, well use the xsl:fallback to transform our document if the Redirect extension cant be found: ?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: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 p a xsl:attribute name=href xsl:value-of select=concatchapter, position+1, .html xsl:attribute Next a p xsl:if body html xsl:fallback xsl:if test=position=1 html head titlexsl:value-of select=booktitletitle head body page 155 xsl:for-each select=bookchapter h1xsl:value-of select=titleh1 xsl:apply-templates select=para xsl:for-each body html xsl:if xsl:fallback redirect:write xsl:for-each xsl:template xsl:template match=para pxsl:apply-templates select=|textp xsl:template xsl:stylesheet In our example, we only invoke the fallback processing once. This approach assumes that if somethings wrong with the extension, it will fail the first time and be completely inaccessible. Using xsl:fallback , we know that the contents of the xsl:fallback element will be invoked if anything goes wrong when the stylesheet processor attempts to use an extension element. If youd like more complete control over fallback processing, you can use the element-available and function-available functions as we did in our earlier example.

8.2 Extending the Saxon Processor

Michael Kays excellent Saxon processor also provides an extension mechanism. One of the nice features of Saxons extensibility mechanism is that you can implement your own sort functions. When we discussed the xsl:sort element a couple of chapters ago, we mentioned that it has a lang attribute that defines the language of the things being sorted. While Xalan doesnt currently support this attribute although by the time youre reading this, it might, Saxon lets you create your own extension function to handle the sorting. Your extension function must extend the com.icl.saxon.sort.TextComparer class. Heres a sample XML document well use to illustrate this function: ?xml version=1.0? wordlist wordcampoword wordlunaword wordciudadword wordllavesword wordchihuahuaword wordarrozword wordlimonadaword wordlist This document contains Spanish words that are sorted differently than they would be in English. In Spanish, ch and ll are separate letters that sort after c and l, respectively. Well write a stylesheet that uses three xsl:template s to illustrate how our extension function works. Heres the stylesheet: ?xml version=1.0? xsl:stylesheet version=1.0 xmlns:xsl=http:www.w3.org1999XSLTransform xsl:output method=text indent=no xsl:strip-space elements= xsl:variable name=newline xsl:text xsl:text xsl:variable xsl:template match= xsl:value-of select=newline xsl:apply-templates select=wordlist mode=unsorted