运行因式的XSL代码时xslt或xml出错

时间:2010-12-18 06:58:38

标签: xml xslt

我已经使用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 &gt; 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?

提前致谢。

2 个答案:

答案 0 :(得分:1)

您的第一个模板与numbers节点匹配,但什么都不做。

您的第二个模板与任何内容都不匹配,并且永远不会被任何其他模板调用。换句话说,它永远不会被执行。

这就是输出为5的原因。


让我们看看会发生什么。在XSLT中,可以通过两种方式调用模板。

  • 首先,它们可以匹配XML输入的元素。你的第一个模板正是这样做的:在原始问题中,它匹配/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 &gt; 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="&#xA;    5&#xA;  ">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