You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:15:01