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

XSLT中按Item/@Id分组并去除子节点重复项的实现

需求:按item/@id分组并去除组内重复的content节点

源XML:

<products>
    <item id="1">
        <content desc="laptop"/>
        <content desc="charger"/>
    </item>
    <item id="1">
        <content desc="laptop"/>
        <content desc="charger"/>
        <content desc="mouse"/>
    </item>
    <item id="2">
        <content desc="laptop"/>
        <content desc="charger"/>
    </item>        
</products>

预期输出:

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <product>
      <id>1</id>
      <detail>
          <item>laptop</item>
          <item>charger</item>
          <item>mouse</item>
      </detail>
   </product>
   <product>
      <id>2</id>
      <detail>
          <item>laptop</item>
          <item>charger</item>
      </detail>
   </product>
</output>

XSLT 1.0 解决方案

1.0版本需使用双重Muenchian分组:先按item/@id分组,再在每组内对content/@desc去重。需定义两个键:

  • 第一个键用于按item/@id分组
  • 第二个键为复合键,结合item/@id和content/@desc,确保仅在同一id组内去重

完整代码:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" encoding="UTF-8"/>
    <xsl:strip-space elements="*"/>

    <!-- 按item的id分组 -->
    <xsl:key name="itemById" match="item" use="@id"/>
    <!-- 复合键:同一item id下的content desc -->
    <xsl:key name="contentByItemIdAndDesc" match="content" use="concat(../@id, '|', @desc)"/>

    <xsl:template match="products">
        <output>
            <!-- 遍历每个唯一的item id组 -->
            <xsl:for-each select="item[generate-id() = generate-id(key('itemById', @id)[1])]">
                <product>
                    <id><xsl:value-of select="@id"/></id>
                    <detail>
                        <!-- 遍历当前id组内所有唯一的content节点 -->
                        <xsl:for-each select="key('itemById', @id)/content[generate-id() = generate-id(key('contentByItemIdAndDesc', concat(../@id, '|', @desc))[1])]">
                            <item><xsl:value-of select="@desc"/></item>
                        </xsl:for-each>
                    </detail>
                </product>
            </xsl:for-each>
        </output>
    </xsl:template>
</xsl:stylesheet>

说明:

  • 复合键用concat(../@id, '|', @desc)拼接id和desc,避免不同id组的相同desc被误判为重复
  • 内层for-each通过key('itemById', @id)获取当前id下的所有item节点,再筛选出唯一的content节点

XSLT 2.0 解决方案

2.0版本支持嵌套分组,写法更简洁:先按item/@id分组,再在组内对所有content节点按@desc分组,取每个分组的第一个节点即可去重。

完整代码:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" encoding="UTF-8"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="products">
        <output>
            <!-- 外层按item id分组 -->
            <xsl:for-each-group select="item" group-by="@id">
                <product>
                    <id><xsl:value-of select="current-grouping-key()"/></id>
                    <detail>
                        <!-- 内层按content desc分组,自动去重 -->
                        <xsl:for-each-group select="current-group()/content" group-by="@desc">
                            <item><xsl:value-of select="@desc"/></item>
                        </xsl:for-each-group>
                    </detail>
                </product>
            </xsl:for-each-group>
        </output>
    </xsl:template>
</xsl:stylesheet>

说明:

  • current-group()获取当前id分组下的所有item节点
  • 内层for-each-group遍历这些item下的所有content,按@desc分组实现去重
  • current-grouping-key()直接获取当前分组的id值,写法更直观

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:05:03