Re: [xsl] Re: RE: syntax sugar for call-template

Subject: Re: [xsl] Re: RE: syntax sugar for call-template
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Fri, 16 Feb 2001 16:44:04 +0000
Hi Dimitre,

> Then this is a good use case, which shows that we need the following:
>
> <xsl:reference-of select="$xpathExpression"/>
>
> This is the counterpart of xsl:copy-of. For each node in
> $xpathExpression its reference will be generated.
>
> By definition, a node-set containing references ("reference-set"???)
> will be indistinguishable from a nodeset containing the original
> nodes.

Interesting idea, although I think it should be thought of as a way of
building up a node set without introducing a new data type to XSLT (or
to the XML Information Set!).

If you made it *only* valid within variable-setting content (i.e. in
xsl:variable, xsl:param and xsl:with-param) you would avoid the
question of what to do if it occurred outside such a context.  The
trouble is that you can't tell whether the content of a template is
going to be outputted to the result tree or held in a variable.  How
should a (reference to a) source tree node be outputted to the result
tree?

And you would probably have to say that if a xsl:reference-of is used
then you could have no other node-generating content.  Otherwise you
end up with node sets containing nodes from the source trees mixed
with new nodes from no tree or something.  Or would it be a RTF with
source nodes mixed with result nodes?

So with those restrictions I could do:

   <xsl:variable name="unique-nodes">
      <xsl:for-each select="$nodes[count(.|key($key, .)[1]) = 1]">
         <xsl:reference-of select="." />
      </xsl:for-each>
   </xsl:variable>

rather than:

   <xsl:variable name="unique-nodes"
                 select="$nodes[count(.|key($key, .)[1]) = 1]" />

[Actually it's possibly more useful than this, coming into its own
when constructing irregular node sets, because there can be multiple
xsl:for-eaches, xsl:ifs and so on in there as well - this is a pretty
simple case.]
                 
However, placing those restrictions on it unfortunately makes it
pretty pointless in this case - I can build up the node set, but still
not return it as a node set: I need xsl:return to do that. And with
xsl:return, I could just do:

<xsl:key name="default-key" match="node()" use="." />
<xsl:template name="my:distinct">
   <xsl:param name="nodes" select="/.." />
   <xsl:param name="key" select="'default-key'" />
   <xsl:return select="$nodes[count(.|key($key, .)[1]) = 1]" />
</xsl:template>

with no reason to build the node set anyway.

If you look at the intersection function, things are slightly more
interesting. With just xsl:return I think you have to use recursion:

<xsl:template name="my:intersection">
   <xsl:param name="nodeset1" select="/.." />
   <xsl:param name="nodeset2" select="/.." />
   <xsl:choose>
      <xsl:when test="$nodeset1">
        <xsl:variable name="rest"
                      select="my:intersection($nodeset[position() &gt; 1],
                                              $nodeset2)" />
        <xsl:return select="$nodeset1[1][count(.|$nodeset2) =
                                         count($nodeset2)] |
                            $rest" />
      </xsl:when>
      <xsl:otherwise>
         <xsl:return select="/.." />
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>

With xsl:reference-of as well, you could do it within an xsl:for-each:

<xsl:template name="my:intersection">
   <xsl:param name="nodeset1" select="/.." />
   <xsl:param name="nodeset2" select="/.." />
   <xsl:return>
      <xsl:for-each select="$nodeset1">
         <xsl:if test="count(.|$nodeset2) = count($nodeset2)">
            <xsl:reference-of select="." />
         </xsl:if>
      </xsl:for-each>
   </xsl:return>
</xsl:template>

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread