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: xsl-list at lists dot mulberrytech dot com
- Date: Mon, 7 Jan 2002 16:40:56 +0000
- Subject: Re: XPath's role (Was: Re: [xsl] Re: . in for)
- Organization: Jeni Tennison Consulting Ltd
- References: <001501c196ee$7f7c7410$465169d5@pcukmka>
- Reply-to: xsl-list at lists dot mulberrytech dot com
Mike Kay wrote:
> Attached, for information, is a position paper which was used during
> the WG deliberations to justify the decision. It was drafted by me
> under the direction of the XSL WG, and accepted by the group.
[snip]
> 3.3 Are range variables needed?
[snip]
> With sequences, it will be much more common to process several
> collections (trees or sequences) at the same time and do joins
> between them. It's easy to find use cases where the single "." is
> obviously inadequate, for example you can't rewrite:
>
> for $i in 1 to 10 return $items[$i]
>
> without a range variable.
>
> In this case you could write
>
> $items[position() < 11]
With a simple mapping operator, you could also do this with:
(1 to 10) -> sublist($items, ., 1)
> but what about
>
> for $i in (count($items) to count($items) - 5) return $items[$i]
Again the sublist() function combined with the simple mapping operator
comes in handy:
(count($items) to count($items) - 5) -> sublist($items, ., 1)
If I was doing this a lot I'd probably write myself a more general
function of the form:
<xsl:function name="my:sublist">
<xsl:param name="seq" type="item*" />
<xsl:param name="positions" type="integer*" />
<xsl:result select="if (empty($positions))
then ()
else ($seq[$positions[1]],
my:sublist($seq,
sublist($positions, 2)))" />
</xsl:function>
and then do:
my:sublist($items, (1 to 10))
my:sublist($items, (count($items) to count($items) - 5))
> Here we are not returning output in document order, so we can't fall
> back on the boolean test against position().
>
> There are plenty of other examples. A more obvious join example is
> to find duplicates in two files, where duplication is tested under a
> collation:
>
> for $i in document('doc1.xml')//item,
> $j in document('doc2.xml')//item
> return
> if (compare($i/@code, $j/@code, 'case-folded-collation"))
> then $i else ()
For this example, you need a recursive function:
<xsl:function name="my:join">
<xsl:param name="is" type="node*" />
<xsl:param name="js" type="node*" />
<xsl:variable name="i" select="$is[1]" />
<xsl:result select="if (empty($is))
then ()
else (if (compare($i/@code, $j/@code,
'case-folded-collation')
then $i
else (),
my:join(sublist($is, 2), $js))" />
</xsl:function>
and a function call that looks like:
my:join(document('doc1.xml')//item,
document('doc2.xml')//item)
Cheers,
Jeni
---
Jeni Tennison
http://www.jenitennison.com/
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list