Xml XQuery中基于变量的动态排序(order by)
我试图在XQuery中实现动态排序。我目前正在使用Saxon PE 9.5进行开发,但将在eXist和marklogic中使用XQuery(或XQuery复数),因此任何使用其模块/函数的答案都可以(希望另一个db将具有相应的模块/函数) 排序基于包含字符串序列的变量。序列中的每个字符串都是元素的名称和可选的“降序” 我尝试了多种方法,但都没有达到预期的效果;尤其是第二类 在下面的示例中,排序是静态的,主要排序为Xml XQuery中基于变量的动态排序(order by),xml,sorting,xquery,marklogic,exist-db,Xml,Sorting,Xquery,Marklogic,Exist Db,我试图在XQuery中实现动态排序。我目前正在使用Saxon PE 9.5进行开发,但将在eXist和marklogic中使用XQuery(或XQuery复数),因此任何使用其模块/函数的答案都可以(希望另一个db将具有相应的模块/函数) 排序基于包含字符串序列的变量。序列中的每个字符串都是元素的名称和可选的“降序” 我尝试了多种方法,但都没有达到预期的效果;尤其是第二类 在下面的示例中,排序是静态的,主要排序为c(升序),次要排序为b(降序) so\uxquery\uquestion.xml
c
(升序),次要排序为b
(降序)
so\uxquery\uquestion.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>
输出
<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>
<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>
<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>
有没有什么方法可以进行动态排序,并将以下内容考虑在内
- 可以将元素名称作为变量传递给排序
- 可以为变量中的元素名称指定可选的“降序”
- 维护变量的顺序(主要排序与次要排序)
- 这是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
不过,我可能会将关键点和方向分为两个不同的变量。在尝试实施@mblakele的建议时,我确实做到了这一点 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>
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>
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>
let$orderby:=('c','b递减'))
让$xml:=doc('file:///C:/SO/so_xquery_question.xml')
返回
{
对于$xml/doc/foo中的$foo
订购人
如果($orderby[1]='b'),则$foo/b else(),
如果($orderby[1]='b descending'),则$foo/b else()降序,
如果($orderby[1]='c'),则$foo/c else(),
如果($orderby[1]='c descending'),则$foo/c else()降序,
如果($orderby[2]='b'),则$foo/b else(),
如果($orderby[2]='b descending'),则$foo/b else()降序,
如果($orderby[2]='c'),则$foo/c else(),
如果($orderby[2]='c descending'),则$foo/c else()降序
返回
$foo
}
输出
<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>
<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>
<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>
a2
b2
c0
a1
b1
c0
a3
b3
c3
我要做的是检查序列中的第一项是否有可能的值,然后检查序列中的第二项。这将确保序列的顺序得以保持
优点:
- 它起作用了
- 它非常冗长,对于我的8个可能的元素名来说会很难看
(128个不同的
语句!!)if
- 它在现实中仍然不起作用李>
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)
xquery版本“3.0”;
让$xml:=
a1
b1
c0
a2
b2
c0
a3
b3
c3
让$order by:=('c','b递减')
让$sort:=
if($order by[1]等式'c'和$order by[2]等式'b')
然后“对于$xml/foo中的$foo,按$foo/c、$foo/b降序返回$foo”
else()
返回
util:eval($sort)
这是冗长的——当然需要填写逻辑(并且可以连接$sort)
我在BaseX和Zorba中看到了基于变量的二次排序的类似问题。我曾经考虑过,但没有尝试过。我的实际数据有8个可能的元素,这些元素可能在
$orderby
变量中指定,并且if
语句的数量将非常多。我会试试看会发生什么。希望eXist能够像marklogic一样处理它+一个很好的建议,我认为我不能让它工作;特别是如果我有两个以上的元素可以排序。即使只是在2上排序,我也不确定如何修改您的建议,使其也能处理值为('c descending','b')
的变量。主要排序总是b
或c
,具体取决于if
语句的顺序。我确实想出了一种方法,但仍然非常冗长。我将添加它作为一个答案,但希望有人有一个更好的解决方案(在eXist和marklogic中都有效)。我有一个类似的排序问题,没有eval,这是我能做的最好的了。不过,存在的问题可能是一个bug。谢谢您的建议。我不确定这对我的实际数据是否可行。对于我来说,有太多的可能性需要考虑,而且代码仍然是可维护的。如果我决定限制排序选项,我可能会走这条路。再次感谢!