XSLT脚本开发:移除首个PL开头uomCodeTo的uomConversion后续元素
XML节点过滤问题解决方案
输入XML
<item> <uomConversion> <convRate>32</convRate> <disableDate/> <uomCodeFrom>EA</uomCodeFrom> <uomCodeTo>CS</uomCodeTo> </uomConversion> <uomConversion> <convRate>864</convRate> <disableDate/> <uomCodeFrom>EA</uomCodeFrom> <uomCodeTo>BX</uomCodeTo> </uomConversion> <uomConversion> <convRate>1762</convRate> <disableDate/> <uomCodeFrom>EA</uomCodeFrom> <uomCodeTo>PLU</uomCodeTo> </uomConversion> <uomConversion> <convRate>1762</convRate> <disableDate/> <uomCodeFrom>EA</uomCodeFrom> <uomCodeTo>PLS</uomCodeTo> </uomConversion> <uomConversion> <convRate>1762</convRate> <disableDate/> <uomCodeFrom>XYZ</uomCodeFrom> <uomCodeTo>ABC</uomCodeTo> </uomConversion> </item>
需求说明
找到第一个uomCodeTo值以PL开头的uomConversion元素,移除该元素之后的所有uomConversion元素,最终保留到该节点为止的内容。
尝试的XSLT(未生效)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- Identity template - copies all nodes and attributes as-is --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- Find the position of the first uomConversion element that starts with PL --> <xsl:variable name="positionToRemove"> <xsl:number count="uomConversion[starts-with(uomCodeTo, 'PL')][1]" level="single"/> </xsl:variable> <!-- Match and remove uomConversion nodes after the first one starting with PL --> <xsl:template match="uomConversion[position() > $positionToRemove]" /> </xsl:stylesheet>
问题分析
原XSLT的核心问题在于xsl:number的使用逻辑错误:count属性用于指定计数的节点规则,而非直接获取目标节点的位置。全局变量positionToRemove的计算结果不符合预期,且在模板匹配中使用position() > $positionToRemove时,position()是相对于当前上下文的节点位置,和全局变量的上下文不匹配,导致无法正确识别需要移除的节点。
正确的XSLT解决方案
以下是能实现需求的XSLT代码:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 标识模板:原样复制所有节点和属性 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 移除第一个符合条件的uomConversion之后的所有同类型节点 --> <xsl:template match="uomConversion[ preceding-sibling::uomConversion[starts-with(uomCodeTo, 'PL')][1] and position() > count(preceding-sibling::uomConversion[starts-with(uomCodeTo, 'PL')][1]/preceding-sibling::uomConversion) + 1 ]"/> </xsl:stylesheet>
逻辑说明
- 标识模板负责复制所有未被特殊模板匹配的节点,保证原有结构不变。
- 第二个模板通过以下逻辑匹配需要移除的节点:
- 先定位第一个
uomCodeTo以PL开头的uomConversion节点 - 计算该节点在兄弟节点中的位置:
count(...) + 1 - 匹配所有位置大于该值的
uomConversion节点,不进行复制(即移除)
- 先定位第一个
预期输出
<item> <uomConversion> <convRate>32</convRate> <disableDate/> <uomCodeFrom>EA</uomCodeFrom> <uomCodeTo>CS</uomCodeTo> </uomConversion> <uomConversion> <convRate>864</convRate> <disableDate/> <uomCodeFrom>EA</uomCodeFrom> <uomCodeTo>BX</uomCodeTo> </uomConversion> <uomConversion> <convRate>1762</convRate> <disableDate/> <uomCodeFrom>EA</uomCodeFrom> <uomCodeTo>PLU</uomCodeTo> </uomConversion> </item>
内容的提问来源于stack exchange,提问作者Greg Reynolds
相关产品推荐
相关产品推荐

