[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] order-by vs xsl:sort


Subject: Re: [xsl] order-by vs xsl:sort
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Fri, 29 Apr 2005 23:30:40 +1000

On 4/29/05, David Carlisle <davidc@xxxxxxxxx> wrote:
>
> I've been toying to see how to express xquery's order by in terms of
> xsl. (There's a question at the end, bonus points for anyone not called
> Michael who even gets that far:-)
>
> here's an example xquery
>
> let $data1:=
> <a>
> <z id="a"><y id="1"/></z>
> <z id="b"><y id="2"/></z>
> <z id="c"><y id="3"/></z>
> <z id="d"><y id="4"/></z>
> <z id="e"><y id="5"/></z>
> </a>
> return
> let $data2:=
> <a>
> <z id="s"><y id="6"/></z>
> <z id="t"><y id="7"/></z>
> <z id="u"><y id="8"/></z>
> </a>
> return
>
> for $i in $data1/z/y, $j in $data2/z/y
> order by ($j/@id - $i/@id)
> return
> concat($i/../@id,$j/../@id)
>
> and here's its output (linebreak added after the xml delcn by hand)
>
> $ saxon8q  order.xq
> <?xml version="1.0" encoding="UTF-8"?>
> es ds et cs dt eu bs ct du as bt cu at bu au
>
> Things to note about this are
> a) the sort key cuts across the diagonal, you can't just sort the i and j
>   axes separately. So you can't simply make this into two nested
>   xsl:for-each each with separate xsl:sort's.
> b) the final result uses data accessed by the parent axis from the items
>   in the sorted sequence so you can't simply build a temporary tree
>   that holds a sequence of elements modelling the tuple with  copies of
>   the items in the sequence as then stuff in the parent axis is lost.
>
> Current best plan is the following XSL
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="2.0"
> >
>
> <xsl:variable name="data1" as="item()">
> <a>
> <z id="a"><y id="1"/></z>
> <z id="b"><y id="2"/></z>
> <z id="c"><y id="3"/></z>
> <z id="d"><y id="4"/></z>
> <z id="e"><y id="5"/></z>
> </a>
> </xsl:variable>
>
> <xsl:variable name="data2" as="item()">
> <a>
> <z id="s"><y id="6"/></z>
> <z id="t"><y id="7"/></z>
> <z id="u"><y id="8"/></z>
> </a>
> </xsl:variable>
>
> <xsl:template name="x">
>
> <xsl:variable name="is" select="$data1/z/y"/>
> <xsl:variable name="ci" select="count($is)"/>
> <xsl:variable name="js" select="$data2/z/y"/>
> <xsl:variable name="cj" select="count($js)"/>
>
> <xsl:for-each select="0 to ($ci * $cj)-1">
> <xsl:sort select="$js[(current() idiv $ci) +1]/@id - $is[(current()  mod
$ci)+1]/@id"/>
> <xsl:sequence select="concat($is[(current()  mod
$ci)+1]/../@id,$js[(current() idiv $ci) +1]/../@id)"/>
> </xsl:for-each>
>
> </xsl:template>
>
> </xsl:stylesheet>
>
> which works:

Isn't this simpler?

<xsl:for-each select=
  "for $i in $data1/z/y, $j in $data2/z/y
        return concat($i/../@id, $j/../@id, string($j/@id - $i/@id))
      ">
  <xsl:sort select="substring(.,3)"/>
   <xsl:sequence select="substring(.,1,2)"/>
</xsl:for-each>


Cheers,
Dimitre Novatchev


Current Thread
Keywords