Monday, 19 September 2011

Difference betweeen apply template and call template

<xsl:call-template> is a close equivalent to calling a function in a traditional programming language.
You can define functions in XSLT, like this simple one that outputs a string.
<xsl:template name="dosomething"> 
  <xsl:text>A function that does something</xsl:text> </xsl:template> 
This function can be called via <xsl:call-template name="dosomething">.
<xsl:apply-templates> is a little different and in it is the real power of XSLT: It takes any number of XML nodes (whatever you define in the select attribute), iterates them (this is important: apply-templates works like a loop!) and finds matching templates for them:
<!-- sample XML snippet --> <xml> 
  <foo /><bar /><baz /> </xml> 
 <!-- sample XSLT snippet --> <xsl:template match="xml"> 
  <xsl:apply-templates select="*" />  
<!-- three nodes selected here --> </xsl:template> 
 <xsl:template match="foo"> <!-- will be called once --> 
  <xsl:text>foo element encountered</xsl:text> </xsl:template> 
 <xsl:template match="xml/*"> <!-- will be called twice --> 
  <xsl:text>other element countered</xsl:text> </xsl:template> 
This way you give up a little control to the XSLT processor - not you decide where the program flow goes, but the processor does by finding the most appropriate match for the node it's currently processing.
If multiple templates can match a node, the one with the more specific match expression wins. If more than one matching template witch the same specificity exist, the one declared last wins.
You can concentrate more on developing templates and need less time to do "plumbing". Your programs will become more powerful and modularized, less deeply nested and faster (as XSLT processors are optimized for template matching).
A concept to understand with XSLT is that of the "current node". With <xsl:apply-templates> the current node moves on with every iteration, whereas <xsl:call-template> does not change the current node. I.e. the . within a called template refers to the same node as the . in the calling template. This is not the case with apply-templates.
This is the basic difference. There are some other aspects of templates that affect their behavior: Their mode and priority, the fact that templates can have both a name and a match. It also has an impact whether the template has been imported (<xsl:import>) or not. These are advanced uses and you can deal with them when you get there.

As with all performance questions, the answer will depend on your particular configuration (in particular the XSLT processor you're using) and the kind of processing that you're doing.
<xsl:apply-templates> takes a sequence of nodes and goes through them one by one. For each, it locates the template with the highest priority that matches the node, and invokes it. So <xsl:apply-templates> is like a <xsl:for-each> with an <xsl:choose> inside, but more modular.
In contrast, <xsl:call-template> invokes a template by name. There's no change to the context node (no <xsl:for-each>) and no choice about which template to use.
So with exactly the same circumstances, you might imagine that <xsl:call-template> will be faster because it's doing less work. But if you're in a situation where either <xsl:apply-templates> or <xsl:call-template> could be used, you're probably going to be doing the <xsl:for-each> and <xsl:choose> yourself, in XSLT, rather than the processor doing it for you, behind the scenes. So in the end my guess it that it will probably balance out. But as I say it depends a lot on the kind of optimisation your processor has put into place and exactly what processing you're doing. Measure it and see.
My rules of thumb about when to use matching templates and when to use named templates are:
  • use <xsl:apply-templates> and matching templates if you're processing individual nodes to create a result; use modes if a particular node needs to be processed in several different ways (such as in the table of contents vs the body of a document)
  • use <xsl:call-template> and a named template if you're processing something other than an individual node, such as strings or numbers or sets of nodes
  • (in XSLT 2.0) use <xsl:function> if you're returning an atomic value or an existing node

No comments:

Post a Comment