This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: XPath's role (Was: Re: Re: . in for)
- From: Jeni Tennison <jeni at jenitennison dot com>
- To: "Michael Kay" <michael dot h dot kay at ntlworld dot com>
- Cc: xsl-list at lists dot mulberrytech dot com
- Date: Mon, 7 Jan 2002 18:27:26 +0000
- Subject: Re: XPath's role (Was: Re: [xsl] Re: . in for)
- Organization: Jeni Tennison Consulting Ltd
- References: <002101c1979c$98cd0570$465169d5@pcukmka>
- Reply-to: xsl-list at lists dot mulberrytech dot com
Hi Mike,
> If it can be shown that user-defined functions can handle all cases
> that would otherwise need range variables, that would certainly be
> an interesting argument to use.
I'm not sure I can *prove* anything (left my mathematical years behind
a while ago), so this is probably something for David or Dimitre. But
isn't it provable from the fact that any iteration over a sequence can
be performed by recursing over the sequence?
Taking the basic example:
for $item in $sequence return some:function($item)
is equivalent to:
<xsl:function name="my:for">
<xsl:param name="sequence" type="item*" />
<xsl:result select="if (empty($sequence))
then ()
else (my:function($sequence[1]),
my:for($sequence[position() > 1]))" />
</xsl:function>
with the call:
my:for($sequence)
Introducing a second range variable:
for $item1 in $sequence1,
$item2 in $sequence2
return some:function($item1, $item2)
is equivalent to:
<xsl:function name="my:for1">
<xsl:param name="sequence1" type="item*" />
<xsl:param name="sequence2" type="item*" />
<xsl:variable name="item1" select="$sequence1[1]" />
<xsl:result select="if (empty($sequence1))
then ()
else (my:for2($item1, $sequence2),
my:for1($sequence1[position() > 1],
$sequence2))" />
</xsl:function>
<xsl:function name="my:for2">
<xsl:param name="item1" type="item" />
<xsl:param name="sequence2" type="item*" />
<xsl:variable name="item2" select="$sequence2[1]" />
<xsl:result select="if (empty($sequence2))
then ()
else (some:function($item1, $item2),
my:for2($item1,
$sequence2[position() > 1]))" />
</xsl:function>
which you would call with:
my:for1($sequence1, $sequence2)
[Note that any filtering of $sequence2 based on the items in
$sequence1 can be handled in some:function() in the general case.]
You can continue doing this ad infinitum, I believe, each time adding
another my:for() function to handle the additional range variable.
Of course there's a difference between proving that you *can* do all
for expressions with user-defined functions and stating that you'd
*want* to do all for expressions with user-defined functions. And I
can quite understand people looking at the above and going 'I'd rather
write a for expression than all of that!'
But in real life, I think the vast majority of the use cases for the
for expression (in XSLT) can be handled with a simple mapping
operator. And hardly any need more than a single function (plus a
simple mapping operator). The existential semantics of the various
comparison operators help enormously, of course. Plus, the only reason
you need to use a function rather than a xsl:for-each (or equivalent)
is if (a) some:function() returns nodes and (b) you don't want to lose
the identity of those nodes.
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list