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

基于匹配规则与节点数量的XML孤儿art节点分组插入问询

处理孤儿ART节点的XQuery解决方案

问题背景

现有XML结构要求正确层级为/nc/mod/grp/art,但存在部分孤儿art节点(路径/nc/mod/art)。需要自动为这些孤儿节点匹配并插入对应的grp节点,匹配规则基于art节点下num值的第二段序列(例如[0-9]{2}-42)。

现有代码问题

尝试的XQuery代码能实现插入,但会为每个匹配的孤儿art节点重复插入grp。由于使用的Saxon处理器不支持group by子句,需要基于distinct-values实现同组匹配的孤儿节点仅插入一次对应grp。

现有代码:

let $input:=doc("file:/C:/Users/FOB/Documents/git_documentation/private/test_mod_art.xml")
    return
        for $ii in $input//mod/art[not(ancestor::grp)] return 
        if ($ii[matches(num, '^[0-5][0-9]-36')]) then
        
        insert node <grp id="d0e1f2f21"><des>GROUP_36</des><num>--36</num><seq>36</seq><des2>GROUP_36</des2></grp> before $ii
        
        else if ($ii[matches(num, '^[0-5][0-9]-42')]) then
        
        insert node <grp id="d0e1f2f23"><des>GROUP_42</des><num>--42</num><seq>42</seq><des2>GROUP_42</des2></grp> before $ii        
        else
        ()

原XML结构

<nc>
    <mod>
        <grp id="d0e9f2f84">
            <des>GROUP_33</des>
            <num>--33</num>
            <seq>33</seq>
            <des2>GROUP_33</des2>
            <art>
                <num>15-33-101-00678</num>
            </art>
        </grp>
        <art>
            <num>15-36-072-00000</num>
        </art>
        <art>
            <num>13-42-099-30002</num>
        </art>
        <art>
            <num>15-42-001-45331</num>
        </art>
    </mod>
    <mod>
        <grp id="d0e9f2f84">
            <des>GROUP_33</des>
            <num>--33</num>
            <seq>33</seq>
            <des2>GROUP_33</des2>
            <art>
                <num>35-33-101-40678</num>
            </art>
        </grp>
        <art>
            <num>11-42-045-41002</num>
        </art>
        <art>
            <num>12-42-101-46331</num>
        </art>
    </mod>
</nc>

期望结果

<nc>
    <mod>
        <grp id="d0e9f2f84">
            <des>GROUP_33</des>
            <num>--33</num>
            <seq>33</seq>
            <des2>GROUP_33</des2>
            <art>
                <num>15-33-101-00678</num>
            </art>
        </grp>
        <grp id="d0e5f2f12">
            <des>GROUP_36</des>
            <num>--36</num>
            <seq>36</seq>
            <des2>GROUP_36</des2>
        </grp>
        <art>
            <num>15-36-072-00000</num>
        </art>
        <grp id="d0e5f2f32">
            <des>GROUP_42</des>
            <num>--42</num>
            <seq>42</seq>
            <des2>GROUP_42</des2>
        </grp>
        <art>
            <num>13-42-099-30002</num>
        </art>
        <art>
            <num>15-42-001-45331</num>
        </art>
    </mod>
    <mod>
        <grp id="d0e9f2f84">
            <des>GROUP_33</des>
            <num>--33</num>
            <seq>33</seq>
            <des2>GROUP_33</des2>
            <art>
                <num>35-33-101-40678</num>
            </art>
        </grp>
        <grp id="d0e5f2f33">
            <des>GROUP_42</des>
            <num>--42</num>
            <seq>42</seq>
            <des2>GROUP_42</des2>
        </grp>
        <art>
            <num>11-42-045-41002</num>
        </art>
        <art>
            <num>12-42-101-46331</num>
        </art>
    </mod>
</nc>

解决方案

核心思路:按每个mod节点独立处理,提取当前mod下孤儿art节点对应的唯一组标识,为每个唯一组仅插入一次grp节点,插入位置为该组第一个孤儿art节点之前。

实现代码:

let $input := doc("file:/C:/Users/FOB/Documents/git_documentation/private/test_mod_art.xml")
return
    copy $copied := $input
    modify (
        for $mod in $copied//mod
        let $orphan-arts := $mod/art[not(ancestor::grp)]
        let $unique-groups := distinct-values(
            for $art in $orphan-arts
            return
                if (matches($art/num, '^[0-5][0-9]-36')) then '36'
                else if (matches($art/num, '^[0-5][0-9]-42')) then '42'
                else ()
        )
        return
            for $group in $unique-groups
            let $first-art := $orphan-arts[matches(num, concat('^[0-5][0-9]-', $group))][1]
            return
                if ($group = '36') then
                    insert node <grp id="d0e5f2f12"><des>GROUP_36</des><num>--36</num><seq>36</seq><des2>GROUP_36</des2></grp> before $first-art
                else if ($group = '42') then
                    insert node <grp id="d0e5f2f32"><des>GROUP_42</des><num>--42</num><seq>42</seq><des2>GROUP_42</des2></grp> before $first-art
                else ()
    )
return $copied

代码说明

  1. 使用copy-modify模式操作XML,避免直接修改源数据
  2. 遍历每个mod节点,单独处理其下的孤儿art节点
  3. 通过distinct-values筛选出当前mod下需要插入的唯一组标识(36、42)
  4. 对每个唯一组,定位该组下第一个孤儿art节点,仅在其前方插入一次对应的grp节点
  5. 不同mod节点的操作相互独立,符合期望结果的分组要求

内容的提问来源于stack exchange,提问作者wiwi_99

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:38:09