初学XSLT的时候一直纠结它对循环的处理,一开始使用for-each进行简单的遍历操作,但是对更精确的循环控制总感觉力不从心。后来我在《XSLT从入门到精通》这本书中看到了一个概念“Side-Effect-Free”-基本意思就是用户不能更新变量值,因此用户对于控制函数环境只有非常有限的能力-才知道XSLT中的variable的值是无法进行二次修改的。因此,类似高级语言(如C++)中如“for(int i = 0; i < n; i++) { }”里的变量i,就不能实现了。后来我又研究了下,XSLT的循环是通过对模板(template)的递归实现的。下面是一段我写的计算圆周率的XSLT代码,使用莱布尼茨级数(Leibniz series)递归求出π/4的近似值,然后输出它的4倍即π的近似值。
1.XML文件“loop.xml”的代码
下面代码中COUNT指定递归次数,即“loop.xslt”中模板CALCULATE的调用次数
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/xsl' href='loop.xslt'?>
<LOOP COUNT="10000" />
2.XSLT文件“loop.xslt”的代码
计算依据:π的莱布尼茨公式(π/4=1-1/3+1/5-1/7+1/9-...)
<?xml version="1.0" encoding="gb2312"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<!--递归计算Pi值-->
<xsl:template name="CALCULATE">
<xsl:param name="LOOP"/>
<xsl:param name="COUNT"/>
<xsl:param name="SIGN"/>
<xsl:param name="VALUE"/>
<xsl:if test="number($LOOP) < number($COUNT) + 1">
<xsl:value-of select ="number($VALUE) * 4"/>
<xsl:text>, </xsl:text>
<xsl:call-template name="CALCULATE">
<xsl:with-param name="LOOP" select="number($LOOP) + 1"/>
<xsl:with-param name="COUNT" select="number($COUNT)"/>
<xsl:with-param name="SIGN" select="number($SIGN) * (-1)"/>
<xsl:with-param name="VALUE" select="number($VALUE) + number($SIGN) div (number($LOOP) * 2 + 1)"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<!--计算Pi值-->
<xsl:template match="/">
<xsl:variable name="INIT_LOOP" select="1"/>
<xsl:variable name="INIT_COUNT" select="/LOOP/@COUNT"/>
<xsl:variable name="INIT_SIGN" select="-1"/>
<xsl:variable name="INIT_VALUE" select="1"/>
<html>
<head>
<meta content="zh-cn" http-equiv="Content-Language"/>
<meta content="text/html; charset=utf-16" http-equiv="Content-Type"/>
<title> π的莱布尼茨公式</title>
</head>
<body>
<xsl:text>计算π值 递归次数:</xsl:text>
<xsl:value-of select="$INIT_COUNT"/>
<hr/>
<xsl:variable name="RESULT" >
<xsl:call-template name="CALCULATE">
<xsl:with-param name="LOOP" select="$INIT_LOOP"/>
<xsl:with-param name="COUNT" select="$INIT_COUNT"/>
<xsl:with-param name="SIGN" select="$INIT_SIGN"/>
<xsl:with-param name="VALUE" select="$INIT_VALUE"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$RESULT"/>
<xsl:text>...</xsl:text>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
3.loop.xml打开后的效果
这个程序迭代10000次后,得出的结果为:3.1414926535900345
附:几个维基百科上的条目
1)函数的副作用:https://en.wikipedia.org/wiki/Side_effect_%28computer_science%29
2)π的莱布尼茨公式:https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80
---------------------------------------------------------------------------------------------------------
后来我又发现了一个更简单高效的方法让XSLT去计算Pi值,即通过在XSLT中嵌入VBScript来完成计算逻辑,详见这篇文章:《在XSLT样式表中插入VBScript脚本进行数学计算》
END