Re: [xsl] First Element in Sorted List

Subject: Re: [xsl] First Element in Sorted List
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Fri, 18 Nov 2005 20:40:52 +1100
On 6/2/05, Michael Kay <mike@xxxxxxxxxxxx> wrote:
> >
> > My process needs to take action on the first element in a list of
> > elements where the logic to determine first is the lowest
> > numeric value
> > of the sortorder attribute.  I don't believe there is a
> > one-line way to
> > do this - I believe the entire list must be sorted, and then the
> > position of each element after sort compared to determine if
> > it is first.
>
> Yes. Even in XSLT 2.0 this may be the best approach. 2.0 offers min/max
> functions, but they give you the highest/lowest value, not the node having
> that value.
>
> Writing a recursive template/function might give you better performance
than
> sorting (linear rather than n*log(n)).
>
> There is a one-line solution: $x[not($x/@sortorder < @sortorder)] but it's
> quite likely to have poor (quadratic) performance.
>
> You could consider using EXSLT math:highest() or math:lowest().
>
> Or I'm sure there's something in Dimitre's box of tricks called FXSL.
>
> Michael Kay
> http://www.saxonica.com/

The following FXSL one-liner does the job:

   <xsl:sequence select=
     "2*f:xsltSort(/*/*/@sortorder/xs:integer(.), f:add(0))[1]"/>


In this case, the "do-something" operation on the minimum item of the
sequence is double-it.

When evaluated against the following source xml:

<t>
 <x sortorder="3"/>
 <x sortorder="2"/>
 <x sortorder="5"/>
 <x sortorder="8"/>
 <x sortorder="7"/>
 <x sortorder="9"/>
 <x sortorder="6"/>
 <x sortorder="4"/>
 <x sortorder="1"/>
 <x sortorder="2"/>
</t>


The correct result:

   2

is produced.

The f:xsltSort() function is simply a wrapper around the

     xsl:perform-sort

instruction. It accepts a list of functions, which are composed to
produce the effect of multiple sort keys. Here's the code of the
function:

 <xsl:function name="f:xsltSort" as="item()*">
   <xsl:param name="pSeq" as="item()*"/>
   <xsl:param name="pCriteria" as="node()*"/>

   <xsl:perform-sort select="$pSeq">
     <xsl:sort select="f:compose-flist($pCriteria, .)"/>
   </xsl:perform-sort>
 </xsl:function>


Certainly, in a future refinement I should also either process an
explicitly passed type-argument (e.g. number or text) or find a way to
efficiently determine the common most non-generic type of all items in
a sequence.

Any ideas?


--
Cheers,
Dimitre Novatchev
---------------------------------------
To avoid situations in which you might make mistakes may be the
biggest mistake of all.

Current Thread