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

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

>> Couldn't agree more strongly.  Thinking about Uche's comments on
>> run-time dynamism and introspection yesterday (I don't know what that
>> means but it sure sounds good) another option would be single new XSLT
>> function:
>> 
>>   call-template('my:func', 'one', xpath,
>>                            'two', $rtf)
>> 
>> I don't know whether this would be more or less acceptable than a
>> means of defining XSLT user extension functions?  The one big
>> limitation is that you wouldn't be able to return node sets (aside
>> from those constructed as an RTF) so there would be limitations on
>> this.
>
> I've been - perhaps lazily - assuming that the implicit RTF -> nodeset
> conversion would convert any node structure into the same structure you
> started with. For instance if I return a node-set of node-sets I'm
> expecting this to be what the calling expression receives. Do you know
> of any exceptions, or are you just being cautious?

Now I'm glad that I sent my previous message about the differences :)
I'll give an example to illustrate the point.  Say that I create a
template that gets nodes with unique values with:

<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:for-each select="$nodes[count(.|key($key, .)[1]) = 1]">
      <xsl:copy-of select="." />
   </xsl:for-each>
</xsl:template>

Now, let's say that I have a set of books with topics on them
(subelements) and I want to group them by topic. Assuming shorthand
syntax with positional parameters, I could get the unique topics with:

   my:distinct(book/topic, 'topics')/topic

(assuming: <xsl:key name="topics" match="book/topic" use="." />)

That might be sufficient.  After all, I could then do:

  book[topic = my:distinct(../book/topic, 'topics')/topic]/name

to get the names of the books. However, I could *not* get the names of
the books with:

  my:distinct(book/topic, 'topics')/topic/parent::book/name

because the only nodes that have been copied into the RTF are the
topic subelements. I've lost the information about ancestry. It's not
a problem if you don't care about ancestry, but you often do. And
there are other things that cause problems, like doing later unions,
using their generated-id() and their base URI.

A way around this is to use references with generate-id() rather than
simply copying the relevant nodes:

<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:for-each select="$nodes[count(.|key($key, .)[1]) = 1]">
      <node id="{generate-id()}" />
   </xsl:for-each>
</xsl:template>

You can then do:

  book/topic[generate-id() =
             my:distinct(../../book/topic, 'topics')/node/@id]

to get the node set that you're after.  It's unweildy, but it would be
usable without introducing a new xsl:return element of any kind.

Cheers,

Jeni

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



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


Current Thread