xml - Dynamic sort (order by), based on variable, in XQuery - TagMerge
6Dynamic sort (order by), based on variable, in XQueryDynamic sort (order by), based on variable, in XQuery

Dynamic sort (order by), based on variable, in XQuery

Asked 1 years ago
2
6 answers

This is a hole in XQuery 1.0, and I don't think 3.0 has fixed it.

For the non-eval approach, have you tried something like this?

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

However I would probably separate the key and direction into two different variables.

Source: link

1

While trying to implement @mblakele's suggestion, I did get this to work...

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>

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>

What I'm doing is checking the first item in the sequence for possible values, then checking the second item in the sequence. This will ensure the order of the sequence is maintained.

Pros:

  • It works.

Cons:

  • It's super verbose and will be ugly for my 8 possible element names (128 different if statements!!).
  • It still doesn't work in eXist.

Source: link

1

In eXist-db, it is possible to get a double sort by using util:eval(). I don't see why this should be necessary, but it works.

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)

It's verbose - and of course the logic needs to be filled out (and you can concatenate $sort).

I see similar problems with secondary sorts based on a variable in BaseX and Zorba.

Source: link

0

Sort array:
const fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
Sort and then reverse the order:
const fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
fruits.reverse();
Syntax
array.sort(compareFunction)
Sort numbers in ascending order:
const points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return a-b});
Sort numbers in descending order:
const points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return b-a});

Source: link

0

By default, the JavaScript Array.sort function converts each element in the array that needs to be sorted into a string, and compares them in Unicode code point order.
const foo = [9, 1, 4, 'zebroid', 'afterdeck'];
foo.sort(); // returns [ 1, 4, 9, 'afterdeck', 'zebroid' ]

const bar = [5, 18, 32, new Set, { user: 'Eleanor Roosevelt' }];
bar.sort(); // returns [ 18, 32, 5, { user: 'Eleanor Roosevelt' }, Set {} ]
It’s also worth noting that unlike many other JavaScript array functions, Array.sort actually changes, or mutates the array it sorts.
const baz = ['My cat ate my homework', 37, 9, 5, 17];
baz.sort(); // baz array is modified
console.log(baz); // shows [ 17, 37, 5, 9, 'My cat ate my homework' ]
To avoid this, you can create a new instance of the array to be sorted and modify that instead. This is possible using an array method that returns a copy of the array. For example, Array.slice:
const sortedBaz = baz.slice().sort(); // a new instance of the baz array is created and sorted
Or if you prefer a newer syntax, you can use the spread operator for the same effect:
const sortedBaz = [...baz].sort(); // a new instance of the baz array is created and sorted
The output is the same in both cases:
console.log(baz); // ['My cat ate my homework', 37, 9, 5, 17];
console.log(sortedBaz); // [ 17, 37, 5, 9, 'My cat ate my homework' ]

Source: link

0

Let’s continue by initializing the following Element objects inside the script tag:
var table = document.getElementById('mytable');var input = document.getElementById('myinput');
Next, create a synthetic array of objects as data to our data.
var tableData = [{name: 'Onion', quantity: 29, price: 1.2, expiry: '2021-09-12'}, {name: 'Apple', quantity: 55, price: 3.3, expiry: '2021-09-22'}, {name: 'Potato', quantity: 25, price: 2.5, expiry: '2021-09-18'}, {name: 'Carrot', quantity: 8, price: 0.8, expiry: '2021-09-25'}];
Continue by defining the following variables which serve as references for toggling between the up and down arrow when table sorting:
var caretUpClassName = 'fa fa-caret-up';var caretDownClassName = 'fa fa-caret-down';
This function works on any data type and can be called as follows:
// assuming that data is an arraydata.sort(sort_by('price', true));
The break statement is removed and the code included a conditional statement that sets the background color to yellow:
cell.style.backgroundColor = 'yellow';

Source: link

Recent Questions on xml

    Programming Languages