This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: XPath's role (Was: Re: Re: . in for)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]