XSLT Extensions
by Bob DuCharme
|
Pages: 1, 2
Using Built-in Extension Functions
An XSLT processor can add additional functions to the selection required of it by the XSLT and XPath specifications. To use one of these extension functions, you only have to declare the namespace and then reference that namespace when calling the function. (When using extension elements, you need the extension-element-prefixes attribute to tell the processor that extension elements from certain namespaces will be used in the stylesheet, but there's no need for this when using extension functions.)
To demonstrate the use of an extension function available in an XSLT processor, we'll look at Xalan Java's tokenize() function, which is similar to the Perl programming language's split() function: it splits up a string whenever it finds a certain character. If you tell it to split up "red,green,light blue" at the commas, you'll get "red", "green" and "light blue". Xalan's tokenize() function accepts two parameters: a string of text delimited by a certain character and an optional string showing the characters used as the delimiter. (The default delimiters are the whitespace characters.) It then splits up the string wherever it finds the delimiting character, creating a node list that your stylesheet can iterate across using an xsl:for-each instruction.
Our stylesheet will use the tokenize() function to split up the fields in the employee elements of the following document:
<employees> <employee>Herbert,Johnny,09/01/1998,95000</employee> <employee>Hill,Graham,08/20/2000,89000</employee> <employee>Hill,Phil,04/23/1999/100000</employee> <employee>Moss,Sterling,10/16/2000,97000</employee> </employees>
|
Also in Transforming XML | |
The following stylesheet converts these employee elements into a table. The two parameters passed to the tokenize() function are "." (an abbreviation of "self::node()", thereby passing the contents of the employee context node) and a comma enclosed in single quotes to show that it's the delimiting character in the first string. The stylesheet also uses the function-available() function that must be supported by all XSLT processors to check whether the tokenize() function is available for use by the stylesheet. If it is, the contents of the xsl:when element get added to the result tree: the tokenize() function splits up the employee contents into a node list and the xsl:for-each instruction goes through that list, adding the contents of each node to the result tree enclosed by an entry element. If the function isn't available, the xsl:otherwise instruction just adds the contents of the source tree employee element inside the row element as one big entry element.
<!-- xq620.xsl: converts xq621.xml into xq622.xml, xq623.xml -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
exclude-result-prefixes="xalan"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="employees">
<table>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="employee">
<row>
<xsl:choose>
<xsl:when test="function-available('xalan:tokenize')">
<xsl:for-each select="xalan:tokenize(.,',')">
<entry><xsl:value-of select="."/></entry>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<entry><xsl:value-of select="."/></entry>
</xsl:otherwise>
</xsl:choose>
</row>
</xsl:template>
</xsl:stylesheet>
For the processor to recognize the function as an extension function, the stylesheet calls tokenize() using the namespace prefix ("xalan") that goes with the declaration identifying the namespace. Because an XSLT processor passes along namespace declarations for any referenced namespaces to the result tree, but we don't want this declaration in our result document, the stylesheet has an exclude-result-prefixes attribute in the xsl:stylesheet element to prevent this.
When run with the Xalan Java processor, the stylesheet splits up each employee element into separate entry elements in each row.
<table> <row><entry>Herbert</entry><entry>Johnny</entry> <entry>09/01/1998</entry><entry>95000</entry></row> <row><entry>Hill</entry><entry>Graham</entry> <entry>08/20/2000</entry><entry>89000</entry></row> <row><entry>Hill</entry><entry>Phil</entry> <entry>04/23/1999/100000</entry></row> <row><entry>Moss</entry><entry>Sterling</entry> <entry>10/16/2000</entry><entry>97000</entry></row> </table>
When run with the Saxon XSLT processor, which doesn't support Xalan's tokenize() function, each employee element gets added to the result tree as one big entry element.
<table> <row><entry>Herbert,Johnny,09/01/1998,95000</entry></row> <row><entry>Hill,Graham,08/20/2000,89000</entry></row> <row><entry>Hill,Phil,04/23/1999/100000</entry></row> <row><entry>Moss,Sterling,10/16/2000,97000</entry></row> </table>
Saxon actually has a tokenize() function, but as Saxon's own extension function, you have to use it by declaring the appropriate namespace and using that namespace to identify the function when calling it. If the stylesheet above were used in a production environment in which Xalan Java and Saxon were both available, the xsl:choose element could include another xsl:when element to check whether saxon:tokenize() is available and to use it if so.
Take a look through your XSLT processor's documentation to see what extension functions are available. Along with debugging features, it's another area where processor developers strive to stand out from the competition, because it's an obvious place to add features unavailable in other processors. It's also a place where developers can address any deficiencies they see in XSLT by adding features they feel should have been there in the first place.
- XSL and html page properties
2002-05-08 02:18:40 Ales Potocnik