|[ Team LiB ]|
16.6 Extension Functions
You learned about external extension functions in the last chapter. You can now add extension functions on the stylesheet level in XSLT 2.0 using the function element. These are called stylesheet functions, but they work like any extension function in an expression. The difference is that they are completely portable between one XSLT 2.0 processor and another.
Example 16-8, function.xsl, uses function to declare a stylesheet function.
Example 16-8. Creating extension functions in XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema-datatypes" xmlns:wy="http://www.wyeast.net/functions"> <xsl:output method="text"/> <xsl:function name="wy:kilometers"> <xsl:param name="miles" as="xs:decimal"/> <xsl:sequence select="$miles * 1.609347"/> </xsl:function> <xsl:template match="/"> <xsl:apply-templates select="trip"/> </xsl:template> <xsl:template match="trip"> <xsl:apply-templates select="distance"/> </xsl:template> <xsl:template match="distance"> <xsl:text>The distance from </xsl:text> <xsl:value-of select="location"/> <xsl:text> to </xsl:text> <xsl:value-of select="destination"/> <xsl:text> is </xsl:text> <xsl:value-of select="round(wy:kilometers(miles))"/> <xsl:text> kilometers. </xsl:text> </xsl:template> </xsl:stylesheet>
When I tested this, it appeared that stylesheet functions must have at least one argument, but this may not be the case, given that 2.0 is still in the early stages. Stylesheet functions must also be identified with a QName that uses a prefix (this is to ensure that user-defined functions don't clash with system-defined functions). The namespace URI and prefix associated with the QName in this example is http://www.wyeast.net/functions and wy:, respectively. It's declared on the stylesheet element.
The function element must be on the top level and declares the stylesheet function named wy:kilometers( ). The function performs a simple conversion of miles to kilometers by accepting a single parameter, miles. Parameters for stylesheet functions are defined with param elements but cannot have default values. The new as attribute on param declares the value of miles as an xs:decimal value, according to the boundaries set by XML Schema datatypes (the namespace is declared on the document element).
The new XSLT 2.0 sequence element adds a sequence of nodes or atomic values to the result tree. In this case, it returns a product (a single atomic value) and works much like value-of. In other situations, you can add existing nodes to a sequence with this element, not just new ones. The factor for converting miles to kilometers (1.609347) comes from the National Institute of Standards and Technology (NIST), and is based on the U.S. survey foot (see http://physics.nist.gov/Pubs/SP811/appenB8.html).
The wy:kilometers( ) function is called later in the stylesheet in a value-of element. It takes a miles node as an argument, and its return value is rounded up or down with the round( ) function. The result is output as text, embedded in a sentence formed from the nodes in the source tree.
Soon, you'll apply this stylesheet to trip.xml, shown in Example 16-9, which holds the road mileage between several U.S. cities.
Example 16-9. Mileage between selected U.S. cities
<?xml version="1.0"?> <trip> <distance> <location>Tucson</location> <destination>Flagstaff</destination> <miles>253</miles> </distance> <distance> <location>Portland</location> <destination>Medford</destination> <miles>272</miles> </distance> <distance> <location>Denver</location> <destination>Colorado Springs</destination> <miles>67</miles> </distance> </trip>
Perform the transformation with:
java -jar saxon7.jar trip.xml function.xsl
You will see this outcome on your screen:
The distance from Tucson to Flagstaff is 407 kilometers. The distance from Portland to Medford is 438 kilometers. The distance from Denver to Colorado Springs is 108 kilometers.
The wy:kilometers( ) stylesheet function may be reused as often as you need it in this stylesheet. A stylesheet function can also be included or imported from another stylesheet.
|[ Team LiB ]|