Variable-based dynamic sorting (in order) in XQuery

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/')))

, ?

  • .
  • "" .
  • ( ).
+4
3

XQuery 1.0, , 3.0 .

- ?

if ($orderby='b') then $foo/b
else if ($orderby='c') then $foo/c else (),
if ($orderby='b descending') then $foo/b
else if ($orderby='c descending') then $foo/c else () descending

, , .

+2

@mblakele, , ...

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[1]='b') then $foo/b else (),
    if ($orderby[1]='b descending') then $foo/b else () descending,
    if ($orderby[1]='c') then $foo/c else (),
    if ($orderby[1]='c descending') then $foo/c else () descending,
    if ($orderby[2]='b') then $foo/b else (),
    if ($orderby[2]='b descending') then $foo/b else () descending,
    if ($orderby[2]='c') then $foo/c else (),
    if ($orderby[2]='c descending') then $foo/c else () descending
    return
        $foo
}</test>

<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>

, , . .

:

  • .

:

  • 8 (128 if!).
  • eXist.
+1

eXist-db : eval(). , , .

xquery version "3.0";
let $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>
let $order-by := ('c','b descending')
let $sort :=
    if ($order-by[1] eq 'c' and $order-by[2] eq 'b descending')
    then 'for $foo in $xml/foo order by $foo/c, $foo/b descending return $foo'
    else ()
return
    util:eval($sort)

- , , ( $sort).

, BaseX Zorba.

+1

Source: https://habr.com/ru/post/1541336/


All Articles