Recipe 6.1. Convert Simple Named Templates to XSLT Functions
Problem
XSLT 1.0 did not support
writing XPath functions in XSLT,
and named templates are an awkward substitute.
Solution
Prefer XSLT 2.0 functions over named templates when the purpose is
solely to compute a result rather then create serialized content.
Below I show a potpourri of examples where functions are much more
convenient compared to named templates:
<!-- Mathematical computations -->
<xsl:function name="ckbk:factorial" as="xs:decimal">
<xsl:param name="n" as="xs:integer"/>
<xsl:sequence select="if ($n eq 0) then 1
else $n * ckbk:factorial($n - 1)"/>
</xsl:function>
<-- Simple mappings -->
<xsl:function name="ckbk:decodeColor" as="xs:string">
<xsl:param name="colorCode" as="xs:integer"/>
<xsl:variable name="colorLookup"
select="('black','red','orange','yellow',
'green','blue','indigo','violet','white')"/>
<xsl:sequence select="if ($colorCode ge 0 and
$colorCode lt count($colorLookup))
then $colorLookup[$colorCode]
else 'no color'"/>
</xsl:function>
<-- String manipulations -->
<xsl:function name="ckbk:reverse">
<xsl:param name="input" as="xs:string"/>
<xsl:sequence select="codepoints-to-string(reverse(
string-to-codepoints($input)))"/>
</xsl:function>
Discussion
Recall that named templates are an alternative to templates that are
invoked strictly by matching. Named templates act much like
procedures in transitional languages because an XSLT programmer
explicitly transfers control to a named template via
xsl:call-tempate, rather than relying on the more
declarative semantics of template matching. A nice feature of XSLT
(both 1.0 and 2.0) is that you can mix these styles by giving a
template both a pattern and a name.
User-defined XSLT 2.0 functions are not a substitute for named
templates. The key question to ask yourself choosing one over the
other is: are you simply computing a result or are you creating a
reusable content producer? The former is better expressed as a
function and the latter as a template. In XSLT 2.0
Programmer's Reference, Michael Kay
recommends using functions in cases where you are simply selecting
nodes and templates when you are creating new ones, even though XSLT
will allow you to use functions for the latter.
This function is selecting nodes:
<xsl:function name="getParts" as="item( )*">
<xsl:param name="startPartId" as="xs:string"/>
<xsl:param name="endPartId" as="xs:string"/>
<xsl:sequence select="//Parts/part[@partId ge $startPartId
and @partId le $endPartId]"/>
</xsl:function>
This function is creating new nodes but perhaps a template would make
more sense:
<xsl:function name="getPartsElem" as="item( )">
<xsl:param name="startPartId" as="xs:string"/>
<xsl:param name="endPartId" as="xs:string"/>
<Parts>
<xsl:copy-of select="//Parts/part[@partId ge $startPartId
and @partId le $endPartId]"/>
<Parts>
</xsl:function>
|