无法在xsl:for-each中顺序递增计数器问题排查
XSLT循环输出内容失效问题分析与解决
问题描述
需求是获取所有同级<Item>节点的数量,通过索引循环输出所有节点的<ItemVal>内容。硬编码索引1和2的代码可正常运行,但将逻辑放入<xsl:for-each>并尝试用计数器递增时失效。
正常工作代码
<fo:flow flow-name="xsl-region-body"> <xsl:variable name="headerCount"> <xsl:value-of select="count(xPath/To/My/Item)"/> </xsl:variable> <xsl:variable name="count" as="xs:integer" select="1"/> <fo:block> <xsl:value-of select="xPath/To/My/Item[$count]/ItemVal"/> <xsl:variable name="count" select="$count+number(1)"/> <xsl:value-of select="xPath/To/My/Item[$count]/ItemVal"/> </fo:block> </fo:flow>
失效代码
<fo:flow flow-name="xsl-region-body"> <xsl:variable name="headerCount"> <xsl:value-of select="count(xPath/To/My/Item)"/> </xsl:variable> <xsl:variable name="count" as="xs:integer" select="1"/> <fo:block> <xsl:for-each select="xPath/To/My/Item"> <xsl:if test="$count &lt;= number($headerItemCount)"> <xsl:value-of select="xPath/To/My/Item[$count]/ItemVal"/> <xsl:variable name="count" select="$count+number(1)"/> </xsl:if> </xsl:for-each> </fo:block> </fo:flow>
错误原因
- XSLT变量不可变特性:XSLT是声明式语言,变量一旦定义就无法修改。你在
<xsl:for-each>内部重新定义的$count是局部变量,和外部的$count相互独立,外部的$count始终保持初始值1,导致每次循环都只会取第一个<Item>的内容。 - 变量名拼写错误:失效代码中判断条件使用了
$headerItemCount,但实际定义的变量是$headerCount,变量名不匹配导致条件判断无效。 - 遍历逻辑冗余:使用
<xsl:for-each select="xPath/To/My/Item">时,当前上下文已经是单个<Item>节点,无需再通过索引[$count]重新定位,直接访问当前节点的ItemVal即可。
解决建议
方案一:直接遍历输出(最简单)
利用<xsl:for-each>的上下文特性,直接输出每个<Item>的<ItemVal>:
<fo:flow flow-name="xsl-region-body"> <fo:block> <xsl:for-each select="xPath/To/My/Item"> <xsl:value-of select="./ItemVal"/> <!-- 如需添加分隔符,可在此处插入,例如:<xsl:text> | </xsl:text> --> </xsl:for-each> </fo:block> </fo:flow>
方案二:需要索引时使用position()函数
如果业务逻辑需要用到循环索引(比如做数量判断),可以使用XSLT内置的position()函数,它会返回当前循环的位置(从1开始):
<fo:flow flow-name="xsl-region-body"> <!-- 直接用select定义数值型变量,无需嵌套xsl:value-of --> <xsl:variable name="headerCount" as="xs:integer" select="count(xPath/To/My/Item)"/> <fo:block> <xsl:for-each select="xPath/To/My/Item"> <!-- 示例:仅输出前N个节点的内容 --> <xsl:if test="position() <= $headerCount"> <xsl:value-of select="./ItemVal"/> </xsl:if> </xsl:for-each> </fo:block> </fo:flow>
额外说明:你最初的正常代码能运行,是因为在同一个作用域内重新定义的$count是新的局部变量,第二个<xsl:value-of>使用的是这个新变量,但这种写法无法推广到循环场景,因为XSLT不支持命令式的变量修改逻辑。
内容的提问来源于stack exchange,提问作者Rito Sarkar
相关产品推荐
相关产品推荐

