Jen*_*sen 4 recursion xquery xquery-3.0
假设我有一个元素<x>x</x>和一些空元素(<a/>, <b/>, <c/>),我想一次包装第二个内部的第一个元素,结果<c><b><a><x>x</x></a></b></c>.当我不知道空元素的数量时,我该怎么做呢?
我可以
xquery version "3.0";
declare function local:wrap-up($inner-element as element(), $outer-elements as element()+) as element()+ {
if (count($outer-elements) eq 3)
then element{node-name($outer-elements[3])}{element{node-name($outer-elements[2])}{element{node-name($outer-elements[1])}{$inner-element}}}
else
if (count($outer-elements) eq 2)
then element{node-name($outer-elements[2])}{element{node-name($outer-elements[1])}{$inner-element}}
else
if (count($outer-elements) eq 1)
then element{node-name($outer-elements[1])}{$inner-element}
else ($outer-elements, $inner-element)
};
let $inner-element := <x>x</x>
let $outer-elements := (<a/>, <b/>, <c/>)
return
local:wrap-up($inner-element, $outer-elements)
Run Code Online (Sandbox Code Playgroud)
但有没有办法通过递归来做到这一点,而不是降序和解析,而是提升和构建?
在函数式编程中,您通常尝试使用列表的第一个元素和尾部,因此规范的解决方案是在嵌套元素之前反转输入:
declare function local:recursive-wrap-up($elements as element()+) as element() {
let $head := head($elements)
let $tail := tail($elements)
return
element { name($head) } { (
$head/@*,
$head/node(),
if ($tail)
then local:recursive-wrap-up($tail)
else ()
) }
};
let $inner-element := <x>x</x>
let $outer-elements := (<a/>, <b/>, <c/>)
return (
local:wrap-up($inner-element, $outer-elements),
local:recursive-wrap-up(reverse(($inner-element, $outer-elements)))
)
Run Code Online (Sandbox Code Playgroud)
是否reverse(...)实际需要反转输出将取决于您的XQuery引擎.最后,反转并不会增加计算复杂性,并且可能不仅会导致代码更清晰,而且执行速度更快!
类似地可以通过将所有内容颠倒来实现,但是在此之前没有用于获取最后一个元素和所有内容的函数,并且在使用谓词last()和时可能会降低性能position() < last().您可以使用XQuery数组,但必须在每个递归函数调用中传递计数器.
最终哪种解决方案最快将需要使用特定的XQuery引擎和代码进行基准测试.