1

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

<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"/>

我正在使用递归模板来计算金额的总和,但只想为特定的 typeOfNode 执行此操作。这是我用来调用模板的代码:

<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>

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

4

4 回答 4

0

我没有看你的代码细节,你为什么不简单地定义一个键

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

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

<xsl:value-of select="sum(key('k1', '1')/@amount)"/>
于 2012-05-31T17:12:36.883 回答
0

如需快速回答,请参阅最后一个代码块。有关代码的一些评论,请从此处阅读。

  1. 如何通过使用 currentValue iso recursiveValue 为 recursiveValue 播种来修复递归循环:

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

    <xsl:variable name="amount" select="//exampleNode[@typeOfNode = '$typeOfnode' and $counter]/@amount"/>
    

    如果你的意思是说“数量是@typeOfNode=$typeofnode 的$counter-th /exampleNode 的@amount,这不是办法。

    • “转义”变量将不起作用,它将与文字值“$typeOfnode”进行比较。
    • "and $counter" 总是计算为真,除非 $counter 没有设置。尝试“position()=$typeOfnode”,但要注意 position 将是当前 exampleNode 在整个 exampleNode 兄弟姐妹集中的位置。这可以通过使用中间变量来解决,在该变量中“复制”通过过滤器的 exampleNodes,您可以使用 $counter 变量在其中测试索引。
  3. 你的片段

        <xsl:with-param name="agreementType">
          <xsl:value-of select="$agreementType"/>
        </xsl:with-param>
    

    可能缺少一些混淆,您的意思是 typeOfnode iso 协议类型吗?:D

除此之外,还有更简单的解决方案。例如一个非常直接的:

<xsl:value-of select="sum(exampleNode[@typeOfnode='1']/@amount)"/>
于 2012-05-31T17:28:28.070 回答
0

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

<?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)。

在递归“函数”中,我们首先测试终端条件,在我们的例子中,“不再累加”。如果是这种情况,返回结果...

...否则,也就是说,如果有更多工作要做,请使用较小的待办事项列表和较高的累加器调用递归部分,这可以保证递归将在某个点停止。

但请参阅我的其他答案以获得更简单的解决方案...

于 2012-05-31T18:11:17.207 回答
0

这里不需要递归!

事实上,想要的总和可以通过一个单行 XPath 表达式返回

sum(/*/*[@typeOfnode = $pType]/@amount)

这是一个完整的转换:

<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>

当此转换应用于以下 XML 文档(提供的片段,包装在单个顶部元素中)时:

<t>
    <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"/>
</t>

产生了想要的正确结果

231
于 2012-06-01T04:00:17.623 回答