@ Test position
My original problem was to simply display a list of elements in a table with
alternate coloring (for even and odd rows).
The obvious answer was "
use the position of the row in the
list".
While this works fine on unordered lists, you get very interesting
effects when you sort the list.
The reason is that the
position returned by the
at $pos
in a
for statement always returns the position of an element related
to the initial list, even if you are sorting the list with
order by.
This is actually the same behavior of an XSLT transformation that uses
<xsl:sort/> (
<xsl:for-each/> or
<xsl:apply-templates>).
But the main advantage of XQuery over XSLT in this case is that with XSLT you
are
trained to avoid the
<xsl:for-each/> statement and
prefer the use of
<xsl:apply-templates> when possible.
In XQuery the
for statement is, instead, one of the main constructs
of the language (the
F in
FLOWR).
This means that we can
abuse the statement, but most importantly
it means that its execution is highly optimized (and also the language
allows for more expressivenes than XSLT).
In this case we can achieve the desired effect by executing 2
for
cycles instead of one.
The first is used to select the elements to list and sort them in a
temporary structure. The second is used to scan the ordered list sequentially
and print it.
And, almost by magic, this time if we query the position of a sorted element
we will get the expected sequentially increasing
index.
The following example illustrates the problem and its solution. The variable
$unordered contains an
unordered list of words. The variable
$ordered is generated by using the first
for cycle to sort the
unordered list. The snippets of code show the result of accessing the list
with or without the
order by modifier.
Variable definition
define variable $unordered
{ "alpha", "zebra", "charlie", "fox", "bravo", "x-ray", "delta", "lima" }
define variable $ordered
{ for $e in $unordered order by $e ascending return $e }
Lists
$unordered: ("alpha", "zebra", "charlie", "fox", "bravo", "x-ray", "delta", "lima")
for $e at $i in $l
return concat(string($i), ":", $e)
1:alpha 2:zebra 3:charlie 4:fox 5:bravo 6:x-ray 7:delta 8:lima$ordered: ("alpha", "bravo", "charlie", "delta", "fox", "lima", "x-ray", "zebra")
for $e at $i in $l
return concat(string($i), ":", $e)
1:alpha 2:bravo 3:charlie 4:delta 5:fox 6:lima 7:x-ray 8:zebraPrint ordered list
for $e at $i in $l
order by $e ascending
return concat(string($i), ":", $e)
1:alpha 5:bravo 3:charlie 7:delta 4:fox 8:lima 6:x-ray 2:zebra
Powered by
MarkLogic Server Standard edition ver. 3.2-1
Send comments or suggestions to
raff@aromatic.org