使用XSLT按同值字段分组XML标签并聚合子节点求助
XSLT按双字段组合分组聚合XML节点实现
需求说明
处理XML中的<Shipment>节点,按<shipFromLocation>(发货地)和<shipToLocation>(收货地)的组合值分组,将同组下所有<Shipment>包含的<container>子节点全部聚合到同一个<Shipment>节点下,同组仅保留一份收发地址字段。
输入XML示例
<?xml version="1.0" encoding="UTF-8"?> <Entity> <Shipment> <shipFromLocation>06AC001</shipFromLocation> <shipToLocation>07BCDAZ</shipToLocation> <container> <key1>101</key1> <key1>102</key1> </container> <container> <key1>103</key1> <key1>104</key1> </container> </Shipment> <Shipment> <shipFromLocation>06AC001</shipFromLocation> <shipToLocation>07BCDAZ</shipToLocation> <container> <key1>105</key1> <key1>106</key1> </container> <container> <key1>107</key1> <key1>108</key1> </container> </Shipment> <Shipment> <shipFromLocation>06AC002</shipFromLocation> <shipToLocation>08BCDAZ</shipToLocation> <container> <key1>200</key1> <key1>201</key1> </container> </Shipment> <Shipment> <shipFromLocation>06AC002</shipFromLocation> <shipToLocation>08BCDAZ</shipToLocation> <container> <key1>202</key1> <key1>203</key1> </container> </Shipment> </Entity>
预期输出XML
<?xml version="1.0" encoding="UTF-8"?> <Entity> <Shipment> <shipFromLocation>06AC001</shipFromLocation> <shipToLocation>07BCDAZ</shipToLocation> <container> <key1>101</key1> <key1>102</key1> </container> <container> <key1>103</key1> <key1>104</key1> </container> <container> <key1>105</key1> <key1>106</key1> </container> <container> <key1>107</key1> <key1>108</key1> </container> </Shipment> <Shipment> <shipFromLocation>06AC002</shipFromLocation> <shipToLocation>08BCDAZ</shipToLocation> <container> <key1>200</key1> <key1>201</key1> </container> <container> <key1>202</key1> <key1>203</key1> </container> </Shipment> </Entity>
原有代码问题
原有XSLT代码存在3个核心错误:
- 分组键设置错误:仅使用
shipFromLocation作为分组依据,未结合shipToLocation做组合判断,会导致发货地相同、收货地不同的节点被错误合并 - 字段输出逻辑错误:循环遍历同组所有Shipment时重复输出
shipFromLocation,且完全遗漏shipToLocation字段 - 节点拷贝逻辑错误:使用
xsl:value-of提取container值,会丢失container下的key1子节点结构,无法保留container的完整层级
正确实现代码
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes" encoding="UTF-8"/> <xsl:template match="/Entity"> <xsl:copy> <!-- 用特殊分隔符拼接收发地址作为组合分组键,避免字段值拼接冲突 --> <xsl:for-each-group select="Shipment" group-by="concat(shipFromLocation, '||', shipToLocation)"> <Shipment> <!-- 同组收发地址完全一致,取组内第一个节点的地址值输出即可 --> <shipFromLocation> <xsl:value-of select="current-group()[1]/shipFromLocation"/> </shipFromLocation> <shipToLocation> <xsl:value-of select="current-group()[1]/shipToLocation"/> </shipToLocation> <!-- 深拷贝同组下所有container节点,完整保留子节点结构 --> <xsl:copy-of select="current-group()/container"/> </Shipment> </xsl:for-each-group> </xsl:copy> </xsl:template> </xsl:stylesheet>
关键逻辑说明
- 分组键使用
concat(shipFromLocation, '||', shipToLocation),选择不会出现在地址编码中的双竖线作为分隔符,避免两个字段值拼接后出现误匹配 - 同组的收发地址完全相同,仅取组内第一个节点的地址字段输出,避免重复生成冗余字段
- 使用
xsl:copy-of直接做深拷贝,一次性把同组所有Shipment下的container节点完整复制到新的Shipment节点下,不需要手动遍历container的子节点,结构不会丢失
内容的提问来源于stack exchange,提问作者Manju Kaushik
相关产品推荐
相关产品推荐

