基于匹配规则与节点数量的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
代码说明
- 使用
copy-modify模式操作XML,避免直接修改源数据 - 遍历每个
mod节点,单独处理其下的孤儿art节点 - 通过
distinct-values筛选出当前mod下需要插入的唯一组标识(36、42) - 对每个唯一组,定位该组下第一个孤儿art节点,仅在其前方插入一次对应的grp节点
- 不同
mod节点的操作相互独立,符合期望结果的分组要求
内容的提问来源于stack exchange,提问作者wiwi_99
相关产品推荐
相关产品推荐

