Calling templates

If you know how to pass parameters to templates, it is very easy to call templates. The only difference between passing and calling is the use of the xsl:call-template instruction instead of the xsl:apply-templates instruction. To see how simple it is, consider the following modification of the previous XSLT:

<xsl:stylesheet version=”1.0”  xmlns:xsl=””>     <xsl:variable name=”globalVariable” select=”/” />     <xsl:template match=”sub” name=”sub”>        <xsl:param name=”functionName” />          [<xsl:value-of select=”$functionName” />]     </xsl:template>     <xsl:template match=”elements”>         <xsl:apply-templates />         <xsl:call-template name=”sub”>             <xsl:with-param name=”functionName” select=”’Hello’”/>         </xsl:call-template>     </xsl:template>     <xsl:template match=”text()”>     </xsl:template> </xsl:stylesheet>

A few changes have been made. The xsl:template match for the XML subnode has the name attribute associated with it. The name attribute identifies the name of the template, which exposes the template as an XSLT function. In the example, both the match and name are identical, which is okay, but not necessary. Within the boundary of the xsl:template match for elements XML nodes, there is an xsl:call-template instruction. The xsl:call-template instruction has the name attribute, which identifies the name of the template that is called. Embedded within the xsl:call-template instruction are the parameters, as in the previous xsl:apply-templates XSLT example. If this XSLT were executed on the original XML document, the result would be as follows:

<?xml version=”1.0” encoding=”UTF-8”?>          [Hello]               []               [Hello]

Some Odd Quirks and How To Solve Them

The output shown in the preceding code block is a bit peculiar because there are two square brackets that contain the Hello text and one square bracket without any generated text. This is an odd result because there should be three cases of the Hello text being generated. This odd result occurs because of the additional xsl:template match of sub. Ignoring the explicit template call, the elements XML nodes that will be matched have the indices of 1 and 2 only. The elements XML node with an index of 3 is not matched because the parent XML subnode has been matched. Within the xsl:template match sub, there is no explicit call to xsl:apply-templates, which means that the XSLT processor considers all child elements as processed.

This is a side effect that we did not want. The remedy to this side effect is to consider your XML data. If the XML data specification has embedded matching tags, as in the case of the elements XML node, then within each xsl:template should be an xsl:apply-templates instruction, as shown by the following modified example:

<xsl:template match=”sub” name=”sub”>    <xsl:apply-templates />    <xsl:param name=”functionName” />      [<xsl:value-of select=”$functionName” />] </xsl:template>

When you execute this modified XSLT document, the following output is generated:

<?xml version="1.0" encoding="UTF-8"?>          [Hello]          [Hello]          []          [Hello]          []          [Hello] 

This output, although better, is a bit too good and generates too many embedded Hello texts and empty texts. The fix that we wanted has generated a new set of problems. This is where an XSLT debugger is absolutely vital. What has happened in this example is that the xsl:apply-templates instruction has executed specific XML nodes in the XML document twice. This is a very good example of the reader needing to use the integrated XML XSLT debugger to see why the nodes are selected again. To solve the double selection problem, consider the following modified XSLT:

<xsl:template match=”sub” name=”sub”>     <xsl:param name=”functionName” />     <xsl:if test=”not($functionName)”>         <xsl:apply-templates select=”child::*”/>     </xsl:if>      [<xsl:value-of select=”$functionName” />] </xsl:template>

The reason for the double selection is that the same template is referenced both from a method call and from a template match. This means that when you use the xsl:call-template instruction, the children are also iterated and matched. This causes the double iteration. To stop the double iteration, an xsl:if instruction can be used to test if the call is a result of a xsl:apply-templates or xsl:call-template. Depending on the test result, the xsl:apply-templates instruction is called. Remember that this only works because xsl:apply-templates is not called with a parameter. Had there been a parameter, it would be impossible to know whether the call was made by xsl:apply-templates or xsl:call-template.

After I say that, some could argue that a check can be made for the current context, or something else. My rebuttal is: Sure. Why not? But then other problems arise. The point is that there is no simple single solution to this problem. The simplest solution is to have two different templates with different identifiers. But then you might have to write two routines to do almost the same thing. The key thing to remember is that XSLT allows a template to be called using two different techniques, and the developer should be aware of that.

The XMLSPY Handbook
The Official XMLSPY Handbook
ISBN: 764549642
EAN: 2147483647
Year: 2001
Pages: 121
Authors: Larry Kim © 2008-2017.
If you may any questions please contact us: