如何用XQuery实现XML按title分组生成book节点?
XML节点分组重构问题
原始XML文件
<books> <title>Moby-Dick</title> <author>Herman Melville</author> <title>Sunrise Nights</title> <author>Jeff Zentner</author> <author>Brittany Cavallaro</author> <price>14.52€</price> <title>My Salty Mary</title> <author>Cynthia Hand</author> <author>Brodi Ashton</author> <author>Jodi Meadows</author> </books>
预期输出
我需要实现的逻辑是:每次遇到<title>节点时,创建一个新的<book>节点,并将后续所有非<title>节点归入该<book>节点下,最终预期输出如下:
<books> <book> <title>Moby-Dick</title> <author>Herman Melville</author> </book> <book> <title>Sunrise Nights</title> <author>Jeff Zentner</author> <author>Brittany Cavallaro</author> <price>14.52€</price> </book> <book> <title>My Salty Mary</title> <author>Cynthia Hand</author> <author>Brodi Ashton</author> <author>Jodi Meadows</author> </book> </books>
尝试的XQuery实现(fold-left方式)
考虑到XQuery的group by不太适配这个按顺序分组的场景,我尝试用fold-left结合数组来实现分组逻辑,代码如下:
补充说明:可能存在更简便的实现方法,欢迎指出。
let $groups := ( doc("books.xml")/books/* => fold-left((array{}, 0), function($acc, $node) { let $arr := $acc[1], $idx := $acc[2] return if (name($node) = "title") then ($arr => array:append($node), $idx+1) else ($arr => array:put($idx, ($arr($idx), $node)), $idx) }) )[1] return <books>{ for $nodes in $groups return <book>{$nodes}</book> }</books>
错误输出
但这段代码运行后结果不符合预期,所有节点被归入了同一个<book>中:
<books> <book> <title>Moby-Dick</title> <author>Herman Melville</author> <title>Sunrise Nights</title> <author>Jeff Zentner</author> <author>Brittany Cavallaro</author> <price>14.52€</price> <title>My Salty Mary</title> <author>Cynthia Hand</author> <author>Brodi Ashton</author> <author>Jodi Meadows</author> </book> </books>
代码修复
我找到了问题所在:遍历数组的方式错误。
错误的遍历写法:
for $nodes in $groups return <book>{$nodes}</book>
正确的写法应该使用数组的array:for-each方法来遍历每个分组:
$groups => array:for-each(function($nodes){<book>{$nodes}</book>})
注:若想了解比
fold-left更简便的实现方法,可参考Stack Exchange上的已采纳答案。
内容的提问来源于Stack Exchange,提问作者Fravadona
相关产品推荐
相关产品推荐

