需要在递归xsl函数中使用xpath按xml节点子集的顺序进行过滤

需要在递归xsl函数中使用xpath按xml节点子集的顺序进行过滤,xml,xslt,xpath,Xml,Xslt,Xpath,我有一组xml节点,它们具有相同的节点名称,但有一个区分它们的属性,还有一个amount属性: <exampleNode typeOfnode="1" amount="100"/> <exampleNode typeOfnode="1" amount="540"/> <exampleNode typeOfnode="2" amount="200"/> <exampleNode typeOfnode="2" amount="200"/> <ex

我有一组xml节点,它们具有相同的节点名称,但有一个区分它们的属性,还有一个amount属性:

<exampleNode typeOfnode="1" amount="100"/>
<exampleNode typeOfnode="1" amount="540"/>
<exampleNode typeOfnode="2" amount="200"/>
<exampleNode typeOfnode="2" amount="200"/>
<exampleNode typeOfnode="3" amount="10"/>
<exampleNode typeOfnode="3" amount="1"/>
<exampleNode typeOfnode="3" amount="110"/>
<exampleNode typeOfnode="3" amount="110"/>
<exampleNode typeOfnode="4" amount="110"/>

我使用一个递归模板来计算数量之和,但只想对特定类型的节点进行计算。下面是我用来调用模板的代码:

<xsl:call-template name="addition">
    <xsl:with-param name="currentValue">0</xsl:with-param>
    <xsl:with-param name="counter"><xsl:value-of select="count(//exampleNode[@typeOfnode= '1'])"/></xsl:with-param>
    <xsl:with-param name="typeOfnode">1</xsl:with-param>
</xsl:call-template>

<xsl:template name="addition">
    <xsl:param name="currentValue"/>
    <xsl:param name="counter"/>
    <xsl:param name="typeOfNode"/>
    <xsl:variable name="amount" select="//exampleNode[@typeOfNode = '$typeOfnode' and $counter]/@amount"/>
    <xsl:variable name="recursiveValue" select="number($recursiveValue + $amount)"/>
    <xsl:choose>
        <xsl:when test="number($counter - 1) > 0">
            <xsl:call-template name="addition">
                <xsl:with-param name="currentValue">
                    <xsl:value-of select="$recursiveValue"/>
                </xsl:with-param>
                <xsl:with-param name="counter">
                    <xsl:value-of select="number($counter - 1)"/>
                </xsl:with-param>
                <xsl:with-param name="agreementType">
                    <xsl:value-of select="$agreementType"/>
                </xsl:with-param>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$recursiveValue"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

0
1.

使用XMLspy进行调试后,未设置amount变量,我认为这是因为我把查询搞砸了。有人知道我做错了什么吗?

我还没有查看代码的详细信息,为什么不简单地定义一个键呢

<xsl:key name="k1" match="exampleNode" use="@typeOfNode"/>

然后计算“1”类型节点的总和,例如

<xsl:value-of select="sum(key('k1', '1')/@amount)"/>

有关快速答案,请参阅最后一个代码块。有关代码的一些注释,请阅读此处

  • 通过使用currentValue iso recursiveValue为recursiveValue种子来修复递归循环如何:

    <xsl:variable name="recursiveValue" select="number($currentValue + $amount)"/>
    
    
    
  • 这里有一些XSLT错误,例如,这看起来不起作用:

    <xsl:variable name="amount" select="//exampleNode[@typeOfNode = '$typeOfnode' and $counter]/@amount"/>
    
    
    
    如果您的意思是说“amount是@typeOfNode=$typeOfNode的$counter th/exampleNode的@amount,那么不是这样的

    • “转义”变量将不起作用,它将与文本值“$typeOfnode”进行比较
    • “和$counter”的计算结果始终为true,除非未设置$counter。请尝试“position()=$typeOfnode”“但请注意,位置将是当前exampleNode在整个exampleNode同级集合中的位置。可以通过使用中间变量“复制”通过过滤器的exampleNodes(使用$counter变量测试索引)来解决这一问题
  • 你的片段

        <xsl:with-param name="agreementType">
          <xsl:value-of select="$agreementType"/>
        </xsl:with-param>
    
    
    
    可能遗漏了一些混淆,您是指节点iso agreementType的类型吗D

  • 除此之外,还有更简单的解决方案。例如一个相当直接的例子:

    <xsl:value-of select="sum(exampleNode[@typeOfnode='1']/@amount)"/>
    

    如果您真的非常想要递归解决方案

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
    
        <xsl:template match="/">
            <xsl:call-template name="recurse">
                <xsl:with-param name="nodes_to_sum" select="//exampleNode[@typeOfnode='1']"/>
                <xsl:with-param name="sum" select="0"/>
            </xsl:call-template> 
        </xsl:template>
    
        <xsl:template name="recurse">
            <xsl:param name="nodes_to_sum"/>
            <xsl:param name="sum"/>
            <xsl:choose>
                <xsl:when test="count($nodes_to_sum)=0">
                    <sum>
                    <xsl:value-of select="$sum"/>        
                    </sum>
                </xsl:when>
                <xsl:otherwise>
    
                    <xsl:call-template name="recurse">
                        <xsl:with-param name="nodes_to_sum" select="$nodes_to_sum[position()>1]"/>
                        <xsl:with-param name="sum" select="$sum + $nodes_to_sum[1]/@amount"/>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
    
        </xsl:template>
    </xsl:stylesheet>
    
    
    
    关于递归

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
    
        <xsl:template match="/">
            <xsl:call-template name="recurse">
                <xsl:with-param name="nodes_to_sum" select="//exampleNode[@typeOfnode='1']"/>
                <xsl:with-param name="sum" select="0"/>
            </xsl:call-template> 
        </xsl:template>
    
        <xsl:template name="recurse">
            <xsl:param name="nodes_to_sum"/>
            <xsl:param name="sum"/>
            <xsl:choose>
                <xsl:when test="count($nodes_to_sum)=0">
                    <sum>
                    <xsl:value-of select="$sum"/>        
                    </sum>
                </xsl:when>
                <xsl:otherwise>
    
                    <xsl:call-template name="recurse">
                        <xsl:with-param name="nodes_to_sum" select="$nodes_to_sum[position()>1]"/>
                        <xsl:with-param name="sum" select="$sum + $nodes_to_sum[1]/@amount"/>
                    </xsl:call-template>
                </xsl:otherwise>
            </xsl:choose>
    
        </xsl:template>
    </xsl:stylesheet>
    
    在第一次调用中,我们初始化数据;整个集合-已过滤-用于计算的和,以及初始和(0)

    在递归“函数”中,我们首先测试终端条件,在我们的例子中,“没有什么可加的了”。如果是这种情况,返回结果

    …否则,也就是说,如果有更多的工作要做,用更小的todo列表和更高的累加器调用递归部分,这保证了递归将在某个点停止


    但请参阅我的另一个答案,以获得更简单的解决方案…

    这里不需要递归

    事实上,所需的总和可以由一个单行XPath表达式返回

    sum(/*/*[@typeOfnode = $pType]/@amount)
    
    231
    
    这里是一个完整的转换:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:param name="pType" select="3"/>
    
     <xsl:template match="/">
      <xsl:value-of select="sum(/*/*[@typeOfnode = $pType]/@amount)"/>
     </xsl:template>
    </xsl:stylesheet>
    

    是的,我在回家的路上意识到了这一点,打了自己一巴掌。不过谢谢你的评论。这篇文章总体上很有帮助,让我对递归函数有了更多的思考。我希望我能给代表,但我的帐户是太noob:)@user1428971笑,无论如何谢谢(说刚出noob家伙)。在你重复了一点之后再回来:D递归确实很强大,但有时有些过分了。我很高兴听到你从中获得了学习的经验。谢谢你走过这段路。