XSLT 1.0需求:重复BATCH元素属性加后缀及校验文本
XSLT 1.0 重复BATCH元素处理修正方案
我需要在XSLT 1.0中实现以下逻辑:当<BATCH>元素文本重复时(首个出现的元素除外),给对应的<MOTOR>元素的No_ID属性添加_1、_2……后缀,同时添加“CHECK IT”文本。
现有的XSLT代码存在两个问题:
- 给首个出现的重复元素也添加了后缀
- 后缀用的是元素的全局位置序号,而非该BATCH值的重复次数序号
输入XML
<ROOT> <MOTORS> <ELEMENT> <NUMBER> <BATCH>ELEC_KN</BATCH> </NUMBER> </ELEMENT> <ELEMENT> <NUMBER> <BATCH>ELEC_LJ</BATCH> </NUMBER> </ELEMENT> <ELEMENT> <NUMBER> <BATCH>DIESEL_ZT</BATCH> </NUMBER> </ELEMENT> <ELEMENT> <NUMBER> <BATCH>ELEC_LJ</BATCH> </NUMBER> </ELEMENT> <ELEMENT> <NUMBER> <BATCH>DIESEL_ZT</BATCH> </NUMBER> </ELEMENT> <ELEMENT> <NUMBER> <BATCH>DIESEL_ZT</BATCH> </NUMBER> </ELEMENT> </MOTORS> </ROOT>
现有XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <Before_sale> <xsl:for-each select="//ROOT/MOTORS/ELEMENT"> <xsl:variable name="BATCH"> <xsl:value-of select="normalize-space(NUMBER/BATCH)"/> </xsl:variable> <xsl:variable name="nameCount" select="count(//ELEMENT[NUMBER/BATCH/text() = current()/NUMBER/BATCH/text()])"/> <xsl:variable name="REPEAT"> <xsl:choose> <xsl:when test="$nameCount > 1"> <xsl:value-of select="$BATCH"/> <xsl:text>_</xsl:text> <xsl:number count="//ELEMENT[NUMBER/BATCH/text() = current()/NUMBER/BATCH/text()]" level="any"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$BATCH"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <MOTOR No_ID="{$REPEAT}"> <xsl:if test="$REPEAT != $BATCH"> <xsl:text> CHECK IT </xsl:text> </xsl:if> </MOTOR> </xsl:for-each> </Before_sale> </xsl:template> </xsl:stylesheet>
期望输出XML
<Before_sale> <MOTOR No_ID="ELEC_KN"/> <MOTOR No_ID="ELEC_LJ"></MOTOR> <!-- 首次出现的元素,不加后缀和校验文本 --> <MOTOR No_ID="DIESEL_ZT"> CHECK IT </MOTOR> <!-- 首次出现的元素,不加后缀和校验文本 --> <MOTOR No_ID="ELEC_LJ_1"> CHECK IT </MOTOR> <!-- 首次重复,添加后缀_1及校验文本 --> <MOTOR No_ID="DIESEL_ZT_1"/> <!-- 首次重复,添加后缀_1 --> <MOTOR No_ID="DIESEL_ZT_2"> CHECK IT </MOTOR> <!-- 第二次重复,添加后缀_2及校验文本 --> </Before_sale>
修正后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <Before_sale> <xsl:for-each select="ROOT/MOTORS/ELEMENT"> <xsl:variable name="currentBatch" select="normalize-space(NUMBER/BATCH)"/> <!-- 计算当前元素是同BATCH值中的第几个实例(从1开始) --> <xsl:variable name="instanceIndex" select="count(preceding-sibling::ELEMENT[NUMBER/BATCH = $currentBatch]) + 1"/> <xsl:variable name="noIdValue"> <xsl:choose> <!-- 仅当不是第一个实例时添加后缀 --> <xsl:when test="$instanceIndex > 1"> <xsl:value-of select="concat($currentBatch, '_', $instanceIndex - 1)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$currentBatch"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <MOTOR No_ID="{$noIdValue}"> <!-- 非首个实例时添加CHECK IT文本 --> <xsl:if test="$instanceIndex > 1"> <xsl:text> CHECK IT </xsl:text> </xsl:if> </MOTOR> </xsl:for-each> </Before_sale> </xsl:template> </xsl:stylesheet>
关键修改说明
- 计算实例序号:使用
count(preceding-sibling::ELEMENT[NUMBER/BATCH = $currentBatch]) + 1获取当前元素在同BATCH值中的位置序号,从1开始计数 - 后缀逻辑调整:仅当
instanceIndex > 1时,用$instanceIndex - 1作为后缀数字,确保首次重复显示_1,第二次重复显示_2 - 条件判断优化:直接通过实例序号判断是否需要添加后缀和文本,避免原代码中对全局计数的错误依赖
内容的提问来源于stack exchange,提问作者runy29
相关产品推荐
相关产品推荐

