如何使用XSLT 1.0移除索引匹配的重复TypeCode节点
问题:移除XSLT转换中索引匹配的重复节点块
尝试多种方法去除重复节点值但未达预期,需要移除索引匹配的重复TypeCode节点块。
输入XML
<before> <class> <type>352</type> <agent>19133</agent> <ins-co>60122</ins-co> </class> <class> <type>351</type> <agent>19355</agent> <ins-co>60122</ins-co> </class> </area> </before> <after> <class> <type>355</type> <agent>19355</agent> <ins-co>60122</ins-co> </class> <class> <type>352</type> <agent>19133</agent> <ins-co>60122</ins-co> </class> </after>
使用的XSLT转换代码
<xsl:template match="/"> <MaintenanceMessage> <BeforeImage> <MaintenanceList> <xsl:apply-templates select="//beforechange/area/stud-class-buckets"> <xsl:with-param name="placement">before</xsl:with-param> </xsl:apply-templates> </MaintenanceList> </BeforeImage> <AfterImage> <MaintenanceList> <xsl:apply-templates select="//beforechange/area/stud-class-buckets"> <xsl:with-param name="placement">after</xsl:with-param> </xsl:apply-templates> </MaintenanceList> </AfterImage> </MaintenanceMessage> </xsl:template> <xsl:template match="//before/class"> <xsl:param name="placement"/> <xsl:variable name="index" select="position()"/> <xsl:if test="//before/class[$index] != //after/class[$index]"> <Maintenance> <xsl:attribute name="index"><xsl:value-of select="$index"/></xsl:attribute> <xsl:variable name="TypeCode"> <xsl:call-template name="FieldValue"> <xsl:with-param name="value" select="dyn:evaluate(concat('//MESSAGE/', $placement , '/class[$index]/type'))"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$TypeCode = 'null'"> <egm:TypeCode xsi:nil="true"/> </xsl:when> <xsl:otherwise> <egm:TypeCode> <xsl:value-of select="$TypeCode"/> </egm:TypeCode> </xsl:otherwise> </xsl:choose> <xsl:variable name="AgentCode"> <xsl:call-template name="FieldValue"> <xsl:with-param name="value" select="dyn:evaluate(concat('//MESSAGE/', $placement , '/class[$index]/agent'))"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$AgentCode = 'null'"> <egm:AgentCode xsi:nil="true"/> </xsl:when> <xsl:otherwise> <egm:AgentCode> <xsl:value-of select="$AgentCode"/> </egm:AgentCode> </xsl:otherwise> </xsl:choose> <xsl:variable name="InsCoCode"> <xsl:call-template name="FieldValue"> <xsl:with-param name="value" select="dyn:evaluate(concat('//MESSAGE/', $placement , '/class[$index]/ins-co'))"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$InsCoCode = 'null'"> <egm:InsCoCode xsi:nil="true"/> </xsl:when> <xsl:otherwise> <egm:InsCoCode> <xsl:value-of select="$InsCoCode"/> </egm:InsCoCode> </xsl:otherwise> </xsl:choose> </Maintenance> </xsl:if> </xsl:template>
当前输出结果
<MaintenanceMessage> <BeforeImage> <MaintenanceList> <Maintenance index="3"> <TypeCode>352</TypeCode> <AgentCode>19133</AgentCode> <InsCoCode>60122</InsCoCode> </Maintenance> <Maintenance index="4"> <TypeCode>351</TypeCode> <AgentCode>19355</AgentCode> <InsCoCode>60122</InsCoCode> </Maintenance> ... </MaintenanceList> </BeforeImage> <AfterImage> <MaintenanceList> <Maintenance index="3"> <TypeCode>355</TypeCode> <AgentCode>19355</AgentCode> <InsCoCode>60122</InsCoCode> </Maintenance> <Maintenance index="4"> <TypeCode>352</TypeCode> <AgentCode>19133</AgentCode> <InsCoCode>60122</InsCoCode> </Maintenance> ... </MaintenanceList> </AfterImage> </MaintenanceMessage>
期望输出结果
<MaintenanceMessage> <BeforeImage> <MaintenanceList> <Maintenance index="3"> <TypeCode>351</TypeCode> <AgentCode>19355</AgentCode> <InsCoCode>60122</InsCoCode> </Maintenance> ... </MaintenanceList> </BeforeImage> <AfterImage> <MaintenanceList> <HazardMaintenance index="3"> <TypeCode>355</TypeCode> <AgentCode>19355</AgentCode> <InsCoCode>60122</InsCoCode> ... </MaintenanceList> </AfterImage> </MaintenanceMessage>
解决方案
当前代码存在以下问题:
- 节点选择路径错误(
//beforechange/area/stud-class-buckets在输入XML中不存在) - 仅通过索引位置对比节点,未识别内容重复(前后class仅顺序调换,核心字段重复)
- 使用非标准
dyn:evaluate扩展,增加复杂度
调整后的XSLT代码如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:egm="http://example.com/egm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- 基于agent+ins-co组合键创建索引,用于去重 --> <xsl:key name="class-by-agent-insco" match="class" use="concat(agent, '|', ins-co)"/> <xsl:template match="/"> <MaintenanceMessage> <BeforeImage> <MaintenanceList> <!-- 只保留before中唯一的class,且与after中同agent+insco的class有type差异的 --> <xsl:apply-templates select="//before/class[generate-id() = generate-id(key('class-by-agent-insco', concat(agent, '|', ins-co))[1])]"> <xsl:with-param name="placement" select="'before'"/> </xsl:apply-templates> </MaintenanceList> </BeforeImage> <AfterImage> <MaintenanceList> <!-- 只保留after中唯一的class,且与before中同agent+insco的class有type差异的 --> <xsl:apply-templates select="//after/class[generate-id() = generate-id(key('class-by-agent-insco', concat(agent, '|', ins-co))[1])]"> <xsl:with-param name="placement" select="'after'"/> </xsl:apply-templates> </MaintenanceList> </AfterImage> </MaintenanceMessage> </xsl:template> <xsl:template match="class"> <xsl:param name="placement"/> <xsl:variable name="current-class" select="."/> <!-- 获取另一个节点集中匹配agent+insco的对应节点 --> <xsl:variable name="matching-class" select=" $placement = 'before' ? //after/class[agent = $current-class/agent and ins-co = $current-class/ins-co] : //before/class[agent = $current-class/agent and ins-co = $current-class/ins-co] "/> <!-- 仅当type不同时输出节点 --> <xsl:if test="$current-class/type != $matching-class/type"> <!-- 根据placement选择节点名称 --> <xsl:element name="{if ($placement = 'after') then 'HazardMaintenance' else 'Maintenance'}"> <xsl:attribute name="index"> <xsl:value-of select="position()"/> </xsl:attribute> <egm:TypeCode> <xsl:value-of select="$current-class/type"/> </egm:TypeCode> <egm:AgentCode> <xsl:value-of select="$current-class/agent"/> </egm:AgentCode> <egm:InsCoCode> <xsl:value-of select="$current-class/ins-co"/> </egm:InsCoCode> </xsl:element> </xsl:if> </xsl:template> <!-- 保留原FieldValue模板处理空值逻辑 --> <xsl:template name="FieldValue"> <xsl:param name="value"/> <xsl:choose> <xsl:when test="$value = '' or not($value)">null</xsl:when> <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
关键修改说明
- 使用
<xsl:key>实现基于agent和ins-co的去重,确保每个唯一组合只处理一次 - 对比前后节点的
type字段,仅当type不同时生成输出,过滤重复内容 - 移除非标准
dyn:evaluate,改用直接节点路径选择,提升代码可读性和兼容性 - 针对AfterImage生成
HazardMaintenance节点,匹配期望输出格式
内容的提问来源于stack exchange,提问作者pks_2014
相关产品推荐
相关产品推荐

