XSLT递归模板应用问题:如何正确计算页面Widget总数?
解决XSLT递归统计出现NaN的问题
问题根源
NaN错误本质是对非数值类型(或空节点集)执行算术运算导致的,常见触发场景:
- 通过
name属性引用的元素不存在,后续求和传入空节点集 - 字符串未转为数值就直接参与运算
- 递归终止条件不明确,返回了非数值结果
具体修复步骤
1. 强制数值转换,空值兜底为0
在所有算术运算前用number()函数包裹,空节点、非数值会被自动转为0,从根源避免NaN。
原错误写法示例:
<xsl:value-of select="sum(//field[@name=current()/@ref]) + count(widget)"/>
修正后:
<xsl:value-of select="number(sum(//field[@name=current()/@ref])) + number(count(widget))"/>
2. 优化元素引用,避免空节点集
用key()提升查找效率,同时确保引用的元素存在,减少空节点集的出现:
首先在XSLT顶部定义键:
<xsl:key name="element-by-name" match="element" use="@name"/>
然后在模板中安全引用:
<xsl:variable name="referenced-element" select="key('element-by-name', @name)"/> <xsl:variable name="referenced-total"> <xsl:apply-templates select="$referenced-element/field"/> </xsl:variable> <!-- 用number()处理递归结果,空值自动转为0 --> <xsl:value-of select="count(widget) + number($referenced-total)"/>
3. 明确递归终止条件
给递归模板添加基础分支,当没有子字段或可引用元素时直接返回当前widget计数:
<!-- 基础分支:无子字段、无引用的field --> <xsl:template match="field[not(@name) and not(field)]"> <xsl:value-of select="count(widget)"/> </xsl:template> <!-- 递归分支:处理有子字段或引用的field --> <xsl:template match="field"> <xsl:variable name="referenced-element" select="key('element-by-name', @name)"/> <xsl:variable name="child-total" select="sum(./field)"/> <xsl:variable name="ref-total"> <xsl:apply-templates select="$referenced-element/field"/> </xsl:variable> <xsl:value-of select="count(widget) + number($child-total) + number($ref-total)"/> </xsl:template>
4. 调试定位问题
添加<xsl:message>输出中间值,快速排查哪一步出现非数值:
<xsl:template match="field"> <xsl:message>当前处理字段:{@name},widget数量:{count(widget)}</xsl:message> <xsl:variable name="referenced-element" select="key('element-by-name', @name)"/> <xsl:message>找到的引用元素数量:{count($referenced-element)}</xsl:message> <!-- 后续递归逻辑 --> </xsl:template>
验证执行
修改完成后重新执行命令:
xsltproc find_depth.xslt has_depth.xml
此时求和结果会以正确数值返回,不再出现NaN。
内容的提问来源于stack exchange,提问作者Quinn Carver
相关产品推荐
相关产品推荐

