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

XSLT过滤XML重复pos属性值元素结果不符预期,求排查

问题:过滤XML中重复属性值的元素

需求

过滤所有具有重复pos属性值的<element>元素,仅保留每个属性值对应的一个元素。

原始XML

<?xml version="1.0" encoding="UTF-8"?>
<elements>
    <element pos="1"/>
    <element pos="2"/>
    <element pos="2"/>
    <element pos="3"/>
</elements>

当前使用的XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:template match="/elements/element">
        <xsl:if test="@pos != preceding-sibling::element/@pos">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:template>
    <xsl:template match="text() | @*"/>
</xsl:stylesheet>

当前错误输出

<?xml version="1.0" encoding="UTF-8"?>
<element pos="2"/>
<element pos="2"/>
<element pos="3"/>

预期输出

<?xml version="1.0" encoding="UTF-8"?>
<element pos="1"/>
<element pos="2"/>
<element pos="3"/>

错误原因

你的<xsl:if>判断逻辑存在问题:
@pos != preceding-sibling::element/@pos 是单个值与节点集合的比较,只要集合里存在任意一个元素不等于当前@pos,条件就会返回true:

  • 第一个<element pos="1">没有前置兄弟,preceding-sibling::element/@pos是空集合,@pos != 空集合返回false,导致该元素被过滤。
  • 第三个<element pos="2">的前置兄弟包含pos="1","2" != "1"为true,所以这个重复元素也被错误保留。

修正方案

方案1:修正判断条件

将<xsl:if>的条件改为检查当前元素是否是该属性值的第一个出现:

<xsl:if test="not(preceding-sibling::element[@pos = current()/@pos])">

这个条件的意思是:不存在任何前置兄弟元素的pos属性等于当前元素的pos属性,确保只保留每个属性值的第一个实例。

完整修正后的XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:template match="/elements/element">
        <xsl:if test="not(preceding-sibling::element[@pos = current()/@pos])">
            <xsl:copy-of select="."/>
        </xsl:if>
    </xsl:template>
    <xsl:template match="text() | @*"/>
</xsl:stylesheet>

方案2:使用XSLT 2.0分组功能(更简洁)

由于你使用的是XSLT 2.0,推荐用<xsl:for-each-group>按@pos分组,直接取每组的第一个元素,逻辑更清晰:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:template match="/elements">
        <xsl:for-each-group select="element" group-by="@pos">
            <xsl:copy-of select="current-group()[1]"/>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 03:25:20