I am trying to implement a dynamic view in XQuery. I'm currently developing Saxon-PE 9.5, but I will use XQuery (or the plural of xqueries) in eXist and marklogic so that any answers using their modules / functions are accurate (and hopefully another db will have the corresponding module / function) .
Sorting is based on a variable that contains a sequence of strings. Each line in the sequence is the name of the element and optional "downstream".
I tried several ways, but I can’t get it to work as it intended; especially for secondary varieties.
In the following example, the sort is static and has a primary view c(ascending) and a secondary view b(descending) ...
so_xquery_question.xml
<doc>
<foo id="foo1">
<a>a1</a>
<b>b1</b>
<c>c0</c>
</foo>
<foo id="foo2">
<a>a2</a>
<b>b2</b>
<c>c0</c>
</foo>
<foo id="foo3">
<a>a3</a>
<b>b3</b>
<c>c3</c>
</foo>
</doc>
Xquery
let $xml := doc('file:///C:/SO/so_xquery_question.xml')
return
<test>{
for $foo in $xml/doc/foo
order by $foo/c, $foo/b descending
return
$foo
}</test>
Output
<test>
<foo id="foo2">
<a>a2</a>
<b>b2</b>
<c>c0</c>
</foo>
<foo id="foo1">
<a>a1</a>
<b>b1</b>
<c>c0</c>
</foo>
<foo id="foo3">
<a>a3</a>
<b>b3</b>
<c>c3</c>
</foo>
</test>
The result is sorted correctly; first c(up) and then b(down).
My last attempt partially works. (In Saxon and marklogic. This does not work the same in eXist for an unknown reason (! @ # $).)
There he is:
Xquery
let $orderby := ('c','b descending')
let $xml := doc('file:///C:/SO/so_xquery_question.xml')
return
<test>{
for $foo in $xml/doc/foo
order by
if ($orderby='b') then $foo/b else (),
if ($orderby='b descending') then $foo/b else () descending,
if ($orderby='c') then $foo/c else (),
if ($orderby='c descending') then $foo/c else () descending
return
$foo
}</test>
Output
<test>
<foo id="foo3">
<a>a3</a>
<b>b3</b>
<c>c3</c>
</foo>
<foo id="foo2">
<a>a2</a>
<b>b2</b>
<c>c0</c>
</foo>
<foo id="foo1">
<a>a1</a>
<b>b1</b>
<c>c0</c>
</foo>
</test>
As you can see, first it is sorted by b(descending). This is because it is the order of the operators ifin order by; not in the order of the variable sequence ( $orderby). If I change the order if(test first c), it will sort normally.
I also had this work in eXist, but it does not process descending:
order by util:eval(concat('$foo/',string-join(tokenize($orderby,'\s')[1],', $foo/')))
, ?