XSLT for-each遍历行时 如何将首个匹配项值赋值给所有后续行
XSLT 2.0 遍历节点时固定引用首个匹配项属性值方案
不需要在目标元素上加额外过滤器,直接利用XSLT变量不可变的特性,提前缓存首个匹配节点的属性值即可实现需求。
核心问题原因
你原有代码在xsl:otherwise分支直接取当前遍历上下文的part属性,xsl:for-each遍历过程中上下文节点会逐行切换,自然会拿到每一行自身的part值,无法固定取首个匹配项的值。
具体实现方法
无自定义排序的场景
如果遍历不需要额外排序,直接在遍历前把符合条件的节点集合、首个节点的part值提前存为变量,遍历过程中直接引用变量即可:
<!-- 缓存所有满足筛选条件的transactionLine节点 --> <xsl:variable name="validLines" select="//transactionLine[@bPALine_l='true']"/> <!-- 持久持有第一个匹配节点的part属性值,变量作用域内值不会变化 --> <xsl:variable name="fixedPartNum" select="$validLines[1]/@part"/> <xsl:for-each select="$validLines"> <record> <!-- 其他字段按原有业务逻辑输出 --> <part_display_number> <xsl:choose> <xsl:when test="position() = 1"> <!-- 第一行输出空值 --> </xsl:when> <xsl:otherwise> <xsl:value-of select="$fixedPartNum"/> </xsl:otherwise> </xsl:choose> </part_display_number> </record> </xsl:for-each>
有自定义排序的场景
如果遍历需要通过xsl:sort自定义排序规则,先把排序后的节点集合缓存后再取首个节点值,避免缓存的首个节点和排序后的第一个节点不一致:
<xsl:variable name="sortedValidLines" as="element()*"> <xsl:perform-sort select="//transactionLine[@bPALine_l='true']"> <!-- 替换成你实际需要的排序规则 --> <xsl:sort select="@createTime" data-type="text" order="ascending"/> </xsl:perform-sort> </xsl:variable> <xsl:variable name="fixedPartNum" select="$sortedValidLines[1]/@part"/> <xsl:for-each select="$sortedValidLines"> <!-- 遍历逻辑和无排序场景完全一致 --> </xsl:for-each>
注意事项
- XSLT中所有变量都是单次赋值、作用域内不可变的,提前把首个匹配项的值存入变量后,不管遍历上下文怎么切换,变量都会持久持有初始化时存入的值,完全满足固定取值的需求。
- 不要在
xsl:for-each内部再写../transactionLine[@bPALine_l='true'][1]/@part这类路径实时查询首个节点,虽然也能拿到值,但每次遍历都会执行一次XPath查询,数据量大时性能比提前缓存变量差很多。
内容的提问来源于stack exchange,提问作者HKmar
相关产品推荐
相关产品推荐

