Re: [xsl] Second of two consecutive call-template instructions appears to affect the first?

Subject: Re: [xsl] Second of two consecutive call-template instructions appears to affect the first?
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Wed, 15 Mar 2006 11:48:58 -0500
Dear Sebastian,

At 05:42 AM 3/15/2006, you wrote:
I hope your class went well.  You may remember that you were going to
quote me as saying "we're just not used to having things done for us
are we?"

Yes, I do, and I did quote you too, and they were appreciative. :-)


Regarding the problem in hand, I just don't get it.  Why should this
work fine:

  <xsl:call-template name="does-image-flickr" />
  .
  .
  <xsl:template name="does-image-flickr">
  <xsl:choose><!-- photo is a flickr link -->
    <xsl:when test="/page/images/image[@name=$name]/flickr">
                                              ^^^^
                                   [variable 'name' is OK]

...and this cause an error:

<xsl:call-template name="does-image-flickr" />
<xsl:call-template name="write-caption">
<xsl:with-param name="cpos"><xsl:value-of select="$cpos" /></xsl:with-param>
<xsl:with-param name="caption"><xsl:value-of select="$caption" /></xsl:with-param>
</xsl:call-template>
.
.
<xsl:template name="does-image-flickr">
<xsl:choose><!-- photo is a flickr link -->
<xsl:when test="/page/images/image[@name=$name]/flickr">
^^^^
[variable 'name' causes an error]


...where the only difference is the call to the 'write-caption'
template that comes _after_ the call to the 'does-image-flickr'
template.

Actually it's not the order that matters at all. Another aspect of the "side-effect-freeness" (freedom from side effects?) of the processing model is that the order of templates matters not a whit. (Actually there are edge cases where it does, but this isn't one of them.)


What matters here is that although you're passing in a value for $cpos with the call, there is no declaration of a 'cpos' parameter in the named template being called.

So write it as

<xsl:template name="does-image-flickr">
  <xsl:param name="cpos" select="''"/>
  <!-- this declaration provides the parameter with an empty string
       as its default value -->
  <xsl:choose><!-- photo is a flickr link -->
    <xsl:when test="/page/images/image[@name=$name]/flickr">

... and you'll be fine. (Or maybe you want to set the default to "false()" or something to avoid getting a selection of a node with @name="").

One adjustment to your idea of how this all works is to keep in mind that when a processor compiles a stylesheet, information about the order of the templates may not be retained. Each template is like a function in itself, which has certain information available to it, which includes the execution context (which node has been matched and so on), but not anything about any local variables in scope in other templates. (This way templates can be executed in parallel, or in an optimized order, without stepping on each other, if the processor so chooses.) Global variables (declared at the top level of the stylesheet) are in scope for all templates, but to pass information between templates, parameters have to be passed, and to provide for that, they have to be declared in any template that has to be aware of them.

The fact that the call to 'does-image-flickr' works in the first
instance proves to me what I have been lead to believe, namely that
call-template differs from apply-templates in that the local scope is
unchanged as well as the current node list.  My experience whilst
writing this template has also served to confirm this.

The execution context is unchanged as far as which node is taken as the current node, the set of nodes in the current node list, etc., but this doesn't include variables declared in a calling template.


  I have several
exapmples where templates called using call-template make use of
params defined in the callee without explicitly passing the params
using with-params.

As long as the parameter is declared in the called template, you're fine; leaving them out of the call just allows them to take the default value, which can be very useful.


But the reverse -- passing a parameter into a template where it isn't defined -- isn't possible. The called template doesn't see such a parameter as being of any interest to it since it hasn't been declared, and when a reference is made to it, it just takes it to be some variable not in scope (which it is).

Like an XML document, a stylesheet in XSLT is not a "script" but rather a tree-shaped thing. Those branches called "templates" present (tree-shaped) chunks of results that will be "grafted" to the output. But internally, the templates have no order: they're just laid out onto the table, as it were, and applied based only on when they match (or are called by name). When that happens, each one is considered to be a self-contained, and special accommodation has to be made for it to "know" anything outside the context of its application. In XSLT 1.0, local variables and parameters fall outside this line. (This has been modified in 2.0 with "tunnel parameters", which are somewhat more flexible, although they too have to be declared in templates where they are actually used, unless I'm mistaken.)

Cheers,
Wendell



======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================

Current Thread