我已经使用xsl计算了xml中给定数字的阶乘的示例。
我的XML代码是fact.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="fact.xsl"?>
<numbers>
<number> 5
</number>
</numbers>
我的XSL代码是fact.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates>
</xsl:apply-templates>
</xsl:template>
<xsl:template name="factorial">
<xsl:param name="number" select="$number"/>
<xsl:param name="result" select="1"/>
<xsl:if test="$number > 1">
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="$number - 1"/>
<xsl:with-param name="result">
<xsl:value-of select="$number * $result"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:if test="$number = 1">
<xsl:value-of select= "$result"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
但是,当我运行此fact.xml时,factorial输出仅显示5
而不是120
。
那么代码中的错误是什么,无论是XML还是XSL?
提前致谢。
答案 0 :(得分:1)
您的第一个模板与numbers
节点匹配,但什么都不做。
您的第二个模板与任何内容都不匹配,并且永远不会被任何其他模板调用。换句话说,它永远不会被执行。
这就是输出为5的原因。
让我们看看会发生什么。在XSLT中,可以通过两种方式调用模板。
/numbers
节点;在您的修订版中,它匹配任何根元素(在这种情况下,相同的东西)。call-template
从模板中调用它们。这就是你在第二个模板中所做的,递归地调用自己。问题是第二个模板只能从...猜测...第二个模板本身。因为它永远不会被调用,所以永远不会执行。
现在,我们将从外部添加对此模板的调用,更准确地说是从第一个模板调用。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="numbers">
<output>
<!-- Here's a missing call to the second template -->
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="number"/>
<xsl:with-param name="result" select="1"/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="factorial">
<xsl:param name="number" />
<xsl:param name="result" />
<intermediary number="{$number}">
<xsl:value-of select="$result"/>
</intermediary>
<xsl:if test="$number > 1">
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="$number - 1"/>
<xsl:with-param name="result" select="$number * $result"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="$number = 1">
<result>
<xsl:value-of select="$result"/>
</result>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
我们还希望确保模板正确执行,因此我们输出中间状态。
<?xml version="1.0" encoding="utf-8"?>
<output>
<intermediary number="
 5
 ">1</intermediary>
<intermediary number="4">5</intermediary>
<intermediary number="3">20</intermediary>
<intermediary number="2">60</intermediary>
<intermediary number="1">120</intermediary>
<result>120</result>
</output>
最终结果是正确的,但第一个中间状态仍然很奇怪。它显示数字5
被视为一个字符串,带有前导和尾随空格。
要摆脱这种情况,必须将number
元素innerXML转换为实数。为此,您可以使用number()
方法:
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="number(number)"/>
<xsl:with-param name="result" select="1"/>
</xsl:call-template>
现在,输出从开始到结束都是正确的,并且可以删除中间输出。
答案 1 :(得分:1)
提供的代码中存在许多错误,兼容的XSLT处理器应该引发它们并且不会产生任何结果。部分/全部错误可能不再可见,因为OP在此期间编辑了他的代码......)。
<xsl:apply-templates match="factorial">
<xsl:apply-templates>
指令没有匹配属性 - 此处引发错误。
<xsl:param name="number" select="$number"/>
这会引发错误,因为此时未定义$number
且无法用于指定参数$number
的默认值。
更重要的错误是从不调用命名模板factorial
。
以下是更正后的代码:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="number[. > 1]" name="factorial">
<xsl:param name="pNumber" select="."/>
<xsl:param name="pResult" select="1"/>
<xsl:choose>
<xsl:when test="$pNumber > 1">
<xsl:call-template name="factorial">
<xsl:with-param name="pNumber"
select="$pNumber -1"/>
<xsl:with-param name="pResult"
select="$pNumber * $pResult"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$pNumber = 1">
<xsl:value-of select= "$pResult"/>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Error</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<numbers>
<number> 5 </number>
</numbers>
产生了想要的正确结果:
120