我带来了:
for $n in $nodes/node()
let $lname := local-name($n)
group by $lname
return element {$lname} {
$n/node()
}
其中$nodes
包含输入文档。
它使用 agroup by
将$n
变量绑定到分组节点列表。因此,表达式$n/node()
表示节点序列。
为了使其递归,我们必须声明一个函数并调用它:
declare function local:recurse($node){
for $n in $node/text() return $n,
for $n in $node/element()
let $lname := local-name($n)
group by $lname
return element {$lname} {
for $m in $n return local:recurse($m)
}
};
local:recurse($nodes)
第一行以逗号结束。这是一个列表连接。因此,我们首先输出文本节点,然后输出带有上述group by
sheningan 的元素节点。
XML 输入
<topic>
<title>Test</title>
<language />
<more-info>
<itunes>
<playlist>
<item>2</item>
</playlist>
<playlist>
<item>3</item>
</playlist>
</itunes>
</more-info>
<more-info>
<imdb>Imdb info</imdb>
</more-info>
<more-info>
<netflix>Netflix info</netflix>
</more-info>
</topic>
XML 输出
<title>Test</title>
<language/>
<more-info>
<itunes>
<playlist>
<item>2</item>
<item>3</item>
</playlist>
</itunes>
<imdb>Imdb info</imdb>
<netflix>Netflix info</netflix>
</more-info>
评论
我不知道为什么认为 XSLT 更容易。也许apply-templates
是在伪装递归,使其不那么令人生畏。
此外,与需要在“循环”内进行匹配的 XQuery 相比,匹配在“循环”之外声明的事实使其更容易(然后,必须与模式配对以进行完全控制)。
无论如何,在这个特殊的例子中,XQuery
似乎是非常合适的。