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
相关产品推荐
相关产品推荐

