Re: [xsl] xsl:script: functions written in XSLT

Subject: Re: [xsl] xsl:script: functions written in XSLT
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Wed, 10 Jan 2001 11:46:56 +0000
Hi Eugene,

Thanks for playing devil's advocate :)  I'm going to shift my argument
a bit to counter your points.

> I was wondering about this when I first saw saxon:function : Is
> there really any difference between that and named templates? If
> not, then why do we need both? should re-think why it is we need
> saxon:function separately from xsl:call-template; not that it causes
> any problems, but it just bothers me that there is a need for two
> different syntaxes that essentially do the same thing!

One way in which saxon:function and xsl:call-template differ is that
saxon:function can return a value of any kind whereas
xsl:call-template always returns a result tree fragment.  In XSLT 1.0,
this means that you can use saxon:function to return a node set
whereas xsl:call-template can't be used in the same way.  That's a big
step because it allows you to do things like find the intersection
between two node sets.

Now, in XSLT 1.1 that's still an issue. xsl:call-template returns a
new node set, with its own root node [these are still result tree
fragments, just without the paucity of processing allowed by XSLT 1.0
result tree fragments]. It will have a different base URI (which means
resolving hrefs might be difficult), may have different relations
between nodes within it and so on.

This means that without a lot of jiggerypokery you cannot implement an
'intersection' XSLT named template that will give you the actual nodes
(not a reconstruction of them) that form the intersection between two
node sets. This is the closest that I could come up with:

<xsl:template name="intersection">
  <xsl:param name="set1" select="../" />
  <xsl:param name="set2" select="../" />
  <xsl:for-each select="$set1">
    <xsl:if test="$set2[count(.|current()) = 1]">
      <item id="{generate-id()}" />

  <xsl:variable name="intersection-items">
    <xsl:call-template name="intersection">
      <xsl:with-param name="set1" select="$set1" />
      <xsl:with-param name="set2" select="$set2" />
  <xsl:variable name="intersection"
                select="$set1[generate-id() =
                              $intersection-items/item/@id" />

It's not particularly important that named templates can't return
boolean, string or numerical values because you can always simulate
them returning those types by returning a text node that you interpret
as a boolean, string or number. However, the fact that it can't return
node sets limits what named templates can be used for. Of course it
doesn't matter now as they're always called with xsl:call-template,
but if we were given the possibility of using named templates as
extension functions then we need something similar to saxon:return to
allow us to return node sets.

> It seems to me terseness was never a high priority in XSLT; One can
> always use XSLScript it it's so important... Actually, the
> convention for abbreviated syntax in xslt is quite strange: for
> instance, why is it ok to comma-separate arguments in a function
> call, but not in an attribute? Is there something inherently wrong
> with <xsl:call-template name="go" with-params="$p1, $p2"/> ?

I agree that terseness wasn't a priority; that doesn't mean it's not
nice to have :)  The xsl:with-param syntax has the good advantage of
using named parameters rather than identifying arguments by position.
I think that can be really useful.

> To allow xsl:script equivalent using existent xsl:template syntax,
> why can't we just use something like xsl:go($p1, $p2). Is it because
> xsl:call-template has used up the xsl: namespace? Is there something
> inherently wrong with assuming that xsl:go is supposed to invoke a
> template with name "go". If so, how about xsl:function:go($p1, $p2)
> ? (being semi-serious here, I know inheritance in namespaces has
> been an issue...) Maybe the safest thing to do would be to come up
> with another namespace for XSL functions, and call
> xsl-function:go($p1, $p2) ?

It's probably safer to allow user-defined namespaces because it avoids
clashes when I have a 'go' template and you have a 'go' template and
I want to use your stylesheet in mine.

> Alternatively, we can define an XSLT function call-template() to
> accept the template name as the first parameter and the template
> params as the rest: <xsl:value-of select="call-template('go', $1,
> $2)"/>

Good suggestion. It's obvious why Javascript (etc) functions need to
be locked away within an xsl:script element. I think that only tried
and tested changes are being worked into XSLT1.1 and unfortunately it
probably plays better to say 'you can define functions in Javascript,
why not in XSLT' than 'let all named templates be called with this new
function or in this new way no matter where they're defined'.

> I suppose since we have xsl:script anyway, we might as well use it,
> but then do we really need the form of xsl:template that takes a
> name? Yes, I know they can have a match as well as a name and be
> kinda overloaded, but what's the point of it?

I don't know and I'd really like to know of a use case - anyone?

> I think the code would look cleaner if the templates were separated
> into two anyway, one with match, one with a name. And btw,
> xsl:script doesn't do anything for verbosity of when invoking the
> <xsl:template match="..."/> form with parameters...

That's true, and I don't think we're going to win the case for XSLT
definitions of function with an argument about verbosity - there's a
better case based on functionality.

I think I can see how user-defined functions in XSLT would be
theoretically useful, but the case would be bolstered a huge amount by
people reporting how they're currently using saxon:function and how
much it's helped them. If there aren't cases like that out there, then
there's not much point in allowing something with similar
functionality in XSLT 1.1.



Jeni Tennison

 XSL-List info and archive:

Current Thread