Re: Designs for XSLT functions (Was: Re: [xsl] RE: syntax sugar for call-template)

Subject: Re: Designs for XSLT functions (Was: Re: [xsl] RE: syntax sugar for call-template)
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Tue, 20 Feb 2001 09:59:49 +0000
Hi David,

>> So you would advocate having the development of exsl:function include
>> adding exsl:if()?
>
> Yes, but the conditional construct cannot be an extension function
> since a function call in XPath evaluates all its parameter *before*
> entering the function. In an if-statement it is crucial that only
> the predicate and one and only one of the clauses get evaluated.
> This means that the conditional construct must be introduced as a
> new special form in the core XPath language. It could be
> syntactically like a function as you suggest e.g. "if ($pred, $true,
> $false)". However you could possibly (and preferably I think) use a
> ternary operator like "$pred ? $true : $false" or even better "if
> $pred then $true else $false" Now, this isn't really the issue here,
> I'm just saying that the conditional construct can take one of many
> forms.

I take your argument, and especially for a different syntax to a
function based if(). I think it's likely that XPath 2.0 will support
such things - it's on their list of requirements. However, I'd like to
focus the discussion on things that we (the community) can achieve
rather than things that only the WG can achieve.

>> I think that the only real objection I would have to this is that
>> conditional constructs in XPath can only go so far and get incredibly
>> messy if they're more that a little complex.  For example:
>
> Well, I think your example doesn't fall far from what's my
> experience of the 80/20 rule here. Of course most functions would be
> more complicated than returning simple numbers but the majority (80%
> to be precise :-) wouldn't be that more complicated. Most of the
> situations where I've felt a need for an xsl:function construct can
> be related to recursive string transformations. In fact, to cope
> with these situations, I'd be satisfied if I could call a named
> template in XPath.

I think I'd personally rather have a "simple things should be easy,
hard things should be possible" rule than a 80/20 rule when designing
this.

I agree that for string manipulation, there's not much call for
anything very sophisticated, and you can always call out to a named
template if you need to.  However, for node-set manipulation that's
not always an option - you can't get a named template to return a node
set.

> This works fine for strings and RTFs, however, xsl:function would
> open a whole new world of other possibilities like recursively
> building up node sets using '|' as the connecting operator. And in
> those situations I would be happy with a simple XPath conditional
> primitive. In fact, as I've implied, I think most of those cases
> would come out more terse and readable than using xsl:chooe etc.

Of course you *can* create conditional node sets without any
requirement for a conditional primitive, e.g.:

  $true[$test] | $false[not($test)]

Again, this becomes pretty unworkable fairly quickly.

>> [Aside: Of course as soon as we have exsl:function we can do:
>> 
>> <exsl:function name="my:if">
>
> [ snip ]
>
>> </exsl:function>
>> 
>> How great is that going to be!]
>
> Sorry, this won't work, see my first paragraph.

Oh, well I'm excited by it anyway.  I *think* that because we're
dealing with a side-effect-free language it shouldn't matter that both
the true and false results are evaluated, aside from in terms of
speed.  And mainly I'm just thinking of things like:

   my:if(@foo = 'yes', 'true', 'false')

where that doesn't matter much.

>>   "It is an error if the result of instantiating the content of
>>   exsl:function involves the creation of any nodes. A processor may
>>   signal this error; if it does not signal the error, it must recover
>>   by ignoring the nodes."
>
> Taking on the hat as an implementor (and user too for that matter)
> I'd prefer static constraints rather than runtime constraints.

Preference noted. Quite a lot of XSLT involves runtime constraints,
for example on the content and placement of xsl:attribute, precisely
because the static constraints are very very hard to articulate.

>> Oh, and I've thought of a couple of reasons to have xsl:for-each.
>> Firstly, as we know, key() and id() are restricted to finding nodes in
>> the current tree. If I want to use an extension function that
>> retrieves keyed nodes in a particular document then I need to be able
>> to do:
>
> [ snip ]
>
> This is addressed in XPath 2.0 Req: 2.1

Sure, and I'm *incredibly* glad to see that. As I said above, though,
I'd like to focus on what is achievable now rather than with XSLT 2.0.
I also think that just because this particular example will be
addressed in XSLT 2.0 doesn't mean that there aren't examples that
won't be.

>> Another example is if I want to use the built-in sort algorithms to
>> find, for example, the first value alphabetically in a node set:
>
> [ snip ]
>
> Yes, that would be nice, and in my proposal you would have to rely
> on RTF to node set conversion to solve this, which could be costly
> in some cases. However, as an implementor I'd prefer some
> declarative solution to this rather than allowing preemptive returns
> from a for-each loop.

For reasons noted previously in this thread, it's not sufficient to
return a copy of the node you want - it has to be the node itself.  In
this example, under your proposal I would have to do:

<exsl:function name="my:first-alphabetical">
   <xsl:param name="nodes" />
   <xsl:variable name="first-node">
      <xsl:for-each select="$nodes">
         <xsl:sort />
         <xsl:if test="position() = 1">
            <xsl:value-of select="generate-id()" />
         </xsl:if>
      </xsl:for-each>
   </xsl:variable>
   <exsl:result select="$nodes[generate-id() = $first-node]" />
</exsl:function>

It's certainly not impossible, just slightly more laborious.

Hmm... perhaps rather than imagining it as a preemptive return we can
imagine it building up exsl:return elements within a result node set.
So essentially the result of calling an exsl:function is a number of
exsl:return instructions.  The first one of those is chosen and the
select expression (or the content) is evaluated to give the value of
the function.  Of course implementers would be free to optimise by
stopping the function when the first exsl:return is generated.

Cheers,

Jeni

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



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


Current Thread