如何用XQuery过滤XML深层子节点的重复项?
解决XML中跨节点的重复/组合去重问题
需求明确:在整个<Articles>文档中,所有<Article>下的<UNIT>节点需保证<NR>与<COUNT>的组合唯一,仅保留该组合第一次出现的<UNIT>节点,后续重复的全部移除。
解决方案:使用XSLT 1.0的Muenchian分组实现去重
Muenchian分组是XSLT中处理节点去重的经典方案,通过定义基于<NR>+<COUNT>组合的键,精准识别重复节点并过滤。
以下是完整的XSLT代码:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义键:用NR和COUNT的文本内容拼接作为唯一标识 --> <xsl:key name="unitKey" match="UNIT" use="concat(NR, '|', COUNT)"/> <!-- 复制所有节点的默认模板 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 过滤重复的UNIT节点:仅保留每个键对应的第一个节点 --> <xsl:template match="UNIT[not(generate-id() = generate-id(key('unitKey', concat(NR, '|', COUNT))[1]))]"/> </xsl:stylesheet>
代码说明
- 键定义:
<xsl:key>将每个<UNIT>节点与NR|COUNT的拼接字符串绑定,这个字符串就是判断重复的唯一标识。 - 默认复制模板:确保原XML中除了需要过滤的
<UNIT>外,其他所有节点(包括<Article>、<A1>等)都被原样复制。 - UNIT过滤模板:当某个
<UNIT>不是其对应键组中的第一个节点时,这个模板会空输出(即移除该节点)。generate-id()函数用于判断节点是否为组内第一个。
使用方法
将上述XSLT保存为remove-duplicate-units.xsl,然后用XML处理器(比如xsltproc命令行工具)处理你的输入XML:
xsltproc remove-duplicate-units.xsl input.xml > output.xml
处理后得到的结果完全符合你的期望输出:保留第一个出现的<NR>/<COUNT>组合对应的<UNIT>,后续重复的全部移除。
对之前尝试的补充说明
你之前用string-join拼接值后删除节点时误删所有<UNIT>,大概率是因为删除逻辑没有精准定位到重复节点,而Muenchian分组通过键组的方式,能准确区分首次出现和重复出现的节点,避免误删。
内容的提问来源于stack exchange,提问作者Alexander D.
相关产品推荐
相关产品推荐

