Previous Page Next Page

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>


Previous Page Next Page