如何在XSLT中删除XML重复项并设置连续序列值(10、20…)
问题:XML中resourceMemberList节点去重并生成递增sequence值
现有XML文件存在重复的resourceMemberList节点,已编写XSLT实现去重逻辑,但需要将去重后的sequence节点设置为10、20这类连续递增的序列值,添加序列设置逻辑时会破坏原有去重功能,寻求可行解决方案。
原XML代码
<?xml version="1.0" encoding="UTF-8"?> <serviceInvocationRequests> <serviceInvocationRequest> <requests> <workCenter>04901</workCenter> <description>Some random description</description> <resourceMemberList> <resource>R4902A01</resource> <sequence>10</sequence> </resourceMemberList> <resourceMemberList> <resource>R4902A02</resource> <sequence>10</sequence> </resourceMemberList> <resourceMemberList> <resource>R4902A01</resource> <sequence>10</sequence> </resourceMemberList> <resourceMemberList> <resource>R4902A02</resource> <sequence>10</sequence> </resourceMemberList> </requests> </serviceInvocationRequest> </serviceInvocationRequests>
现有去重XSLT代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes" method="xml"/> <xsl:strip-space elements="*"/> <xsl:key match="resourceMemberList" name="group-key" use="concat(resource, '|')"/> <xsl:template match="node() | @*"> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> </xsl:template> <xsl:template match="resourceMemberList[generate-id() = generate-id(key('group-key', concat(resource, '|'))[1])]"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="resourceMemberList"/> </xsl:stylesheet>
期望输出XML
<?xml version="1.0" encoding="UTF-8"?> <serviceInvocationRequests> <serviceInvocationRequest> <requests> <workCenter>04901</workCenter> <description>Some random description</description> <resourceMemberList> <resource>R4902A01</resource> <sequence>10</sequence> </resourceMemberList> <resourceMemberList> <resource>R4902A02</resource> <sequence>20</sequence> </resourceMemberList> </requests> </serviceInvocationRequest> </serviceInvocationRequests>
解决方案
修改后的XSLT将保留Muenchian分组去重逻辑,同时为每个唯一的resourceMemberList生成递增的sequence值:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes" method="xml"/> <xsl:strip-space elements="*"/> <xsl:key match="resourceMemberList" name="group-key" use="resource"/> <!-- 身份模板:复制所有未被特殊匹配的节点和属性 --> <xsl:template match="node() | @*"> <xsl:copy> <xsl:apply-templates select="node() | @*"/> </xsl:copy> </xsl:template> <!-- 匹配requests节点,遍历所有唯一的resourceMemberList --> <xsl:template match="requests"> <xsl:copy> <xsl:apply-templates select="node()[not(self::resourceMemberList)]"/> <!-- 按顺序处理每个唯一的resourceMemberList --> <xsl:for-each select="resourceMemberList[generate-id() = generate-id(key('group-key', resource)[1])]"> <xsl:copy> <xsl:apply-templates select="resource"/> <!-- 生成递增的sequence值:位置*10 --> <sequence> <xsl:value-of select="position() * 10"/> </sequence> </xsl:copy> </xsl:for-each> </xsl:copy> </xsl:template> <!-- 忽略所有原始的resourceMemberList节点,避免重复输出 --> <xsl:template match="resourceMemberList"/> </xsl:stylesheet>
逻辑说明
- 保留去重逻辑:依然使用Muenchian分组,通过
key按resource值对resourceMemberList分组,确保每个resource只保留一个实例。 - 重新生成sequence:在
requests节点的模板中,先复制除resourceMemberList外的所有子节点,再遍历所有唯一的resourceMemberList,用position() * 10生成10、20、30...的递增序列值。 - 避免冲突:单独处理
requests节点下的resourceMemberList输出,同时忽略原始的resourceMemberList节点,确保去重和序列生成逻辑互不干扰。
内容的提问来源于stack exchange,提问作者Maksim Sirotkin
相关产品推荐
相关产品推荐

