在XPath谓词中使用distinct-values:XML重复节点集过滤问题
嘿,我来帮你搞定这个XPath 2.0过滤重复节点的问题!先补全你的示例XML方便演示(假设第三个card是不同的条目):
<?xml version="1.0" encoding="utf-8"?> <test> <card> <TimeCard>1234</TimeCard> <tax>HST</tax> <adjAmt>-112</adjAmt> </card> <card> <TimeCard>1234</TimeCard> <tax>GST</tax> <adjAmt>-112</adjAmt> </card> <card> <TimeCard>5678</TimeCard> <tax>HST</tax> <adjAmt>-200</adjAmt> </card> </test>
从你的示例来看,核心需求应该是基于TimeCard和adjAmt的组合值去重(前两个card的这两个字段完全一致,只有tax不同),下面给你两种实用的XPath 2.0方案:
方案1:用for-each-group分组取唯一值(推荐)
XPath 2.0支持for-each-group语法,可以直接按指定字段分组后取每组的第一个节点:
for $group in /test/card group by concat(TimeCard, '|', adjAmt) return $group[1]
- 这里用
concat(TimeCard, '|', adjAmt)把两个字段拼接成唯一分组键(用|分隔是避免字段值本身包含特殊字符导致冲突) $group[1]表示保留每组的第一个节点,如果想保留最后一个,改成$group[last()]即可
方案2:用节点比较过滤重复项
如果你习惯用传统的节点遍历写法,也可以这样写:
/test/card[not(. is following-sibling::card[TimeCard=current()/TimeCard and adjAmt=current()/adjAmt][1])]
这个逻辑是:只保留那些后面没有相同TimeCard+adjAmt组合节点的条目,本质上也是去重。
额外场景:全节点内容去重
如果你的需求是严格判断整个card节点的所有内容(包括tax)是否完全重复,可以用deep-equal函数:
/test/card[not(. is following-sibling::card[deep-equal(., current())][1])]
deep-equal会递归比较两个节点的结构和所有子节点值,只有完全一致才会被判定为重复。
如果你的去重逻辑有其他调整(比如按更多字段分组),只要修改分组键或者比较条件就可以啦!
内容的提问来源于stack exchange,提问作者Zor
相关产品推荐
相关产品推荐

