2012-07-31 69 views
1

下面的XML文档表示3号,2,2和2,一种节点<s>被计数为一个数字,并用<zero/>结束。XSLT递归乘法

<?xml version="1.0" encoding="UTF-8"?> 
    <nat xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="nat.xsd"> 
     <s> 
     <s> 
      <zero/> 
     </s> 
     </s> 
     <s> 
     <s> 
      <zero/> 
     </s> 
     </s> 
     <s> 
     <s> 
      <zero/> 
     </s> 
     </s> 
    </nat> 

我刚开始学习xslt,这是递归练习之一。我可以递归地加上所有数字,但是这个乘以两个以上的数字只是让我大开眼界。我不知道该怎么做。

以上XML文档的预期的答案是787-8(忽略格式):

<s><s><s><s><s><s><s><s><zero/></s></s></s></s></s></s></s></s> 我的想法是这样的,我可以有一个模板,加入做乘法两个数。所以对于这个2x2x2,我会做第二次2次返回4的第三次2,最后做2 * 4。但是,不像java或scheme,call模板不会在xslt中返回值,所以我很欣赏任何提示/帮助。

更新: 我得到了我的答案,在打印模板中添加到Dimitre的答案。那就是:

<xsl:template name="print"> 
    <xsl:param name="pAccum"/> 
     <xsl:choose> 
      <xsl:when test="$pAccum > 0"> 
       <s> 
        <xsl:call-template name="print"> 
         <xsl:with-param name="pAccum" select="$pAccum - 1"/> 
        </xsl:call-template> 
       </s> 
      </xsl:when> 
      <xsl:otherwise> 
       <zero/> 
      </xsl:otherwise>  
     </xsl:choose> 
</xsl:template> 
+0

这似乎不是一个合适的锻炼递归 - - 为什么你不尝试一个更简单和更明确的问题?有:' > > >'并找到所有'num'元素的乘积。 – 2012-07-31 03:56:57

+1

您对模板的评论让您听起来好像您想在XSLT 1.0中执行此操作一样。如果你真的需要使用已经取代近6年的语言版本,你应该在你的文章中这样说。那么对于我们这些对XSLT 1.0来说是一个遥远的衰落内存的人来说,不需要麻烦回答。 – 2012-07-31 08:00:53

+0

@MichaelKay:哎哟,对于模糊评论我很抱歉。这是针对XSLT 2.0的。正如我在试图解决这个问题时想的那样大声。 – bili 2012-07-31 12:58:37

回答

1

这种转变

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:call-template name="product"> 
    <xsl:with-param name="pArgs" select="//zero"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="product"> 
    <xsl:param name="pAccum" select="1"/> 
    <xsl:param name="pArgs" select="/.."/> 

    <xsl:choose> 
    <xsl:when test="not($pArgs)"> 
    <xsl:value-of select="$pAccum"/> 
    </xsl:when> 
    <xsl:otherwise> 
    <xsl:call-template name="product"> 
    <xsl:with-param name="pAccum" 
      select="$pAccum * count($pArgs[1]/ancestor::s)"/> 
    <xsl:with-param name="pArgs" select="$pArgs[position() > 1]"/> 
    </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

时所提供的XML文档应用:

<nat> 
    <s> 
     <s> 
      <zero/> 
     </s> 
    </s> 
    <s> 
     <s> 
      <zero/> 
     </s> 
    </s> 
    <s> 
     <s> 
      <zero/> 
     </s> 
    </s> 
</nat> 

产生想要的,正确的结果:

8 

说明

原始递归与停止条件 - 空的参数节点集合和蓄能器 - 参数用于使当前累加结果到下一个递归调用。

+0

+1正确的答案,但不是显示8就应该显示。有8 表示结束。 – bili 2012-07-31 14:44:00

+0

谢谢!它很好地工作。我通过调试器运行了解决方案,并添加到模板中以获取答案的正确表示。看到我上面的编辑! – bili 2012-07-31 15:44:29

+0

@bili:不客气。是的,我完全忽略了这种相当奇怪的格式。我不知道你想要一个XSLT 2.0解决方案 - 在这种情况下,使用'xsl:finction'更方便。另外,如果你对这个主题感兴趣,你可能会发现它有趣的阅读FXSL:http://conferences.idealliance.org/extreme/html/2006/Novatchev01/EML2006Novatchev01.html – 2012-07-31 16:02:06

1

在XSLT 2.0我会用一对函数开始:

<xsl:function name="f:toNumber" as="xs:integer"> 
    <xsl:param name="z" as="element(zero)"/> 
    <xsl:sequence select="count($z/ancestor::*)"/> 
</xsl:function> 

<xsl:function name="f:fromNumber" as="element()> 
    <xsl:param name="z" as="xs:integer"/> 
    <xsl:choose> 
    <xsl:when test="$z=0"><zero/></xsl:when> 
    <xsl:otherwise><s><xsl:sequence select="f:fromNumber($z - 1)"/> 
</xsl:function> 

铲球您的数字表示的怪事。

现在你只需要一个计算数字序列的产品功能:

<xsl:function name="f:product" as="xs:integer"> 
    <xsl:param name="in" as="xs:integer"/> 
    <xsl:sequence select="if (count($in) = 1) then $in[1] else $in * f:product($in[position()>1])"/> 
</xsl:function> 

,剩下的就是孩子们的游戏...

+0

谢谢你的回答! – bili 2012-07-31 22:28:40