1

同じノード名を持つ一連の xml ノードがありますが、それらを区別する 1 つの属性と、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"/>

金額の合計を計算するために再帰テンプレートを使用していますが、特定の 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 を使用してデバッグしたところ、amount 変数が設定されていません。これは、クエリを台無しにしていることが原因だと思います。誰かが私が間違っていることを知っていますか?

4

4 に答える 4

0

ここでは再帰は必要ありません!

実際、必要な合計は、単一の1ライナー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 に答える
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"/>
    

    「amount は、@typeOfNode=$typeofnode の $counter-th /exampleNode の @amount である」と言いたい場合、これは正しくありません。

    • 変数の「エスケープ」は機能せず、リテラル値「$typeOfnode」と比較されます。
    • $counter が設定されていない限り、"and $counter" は常に true と評価されます。「position()=$typeOfnode」を試してみてください。ただし、position は、exampleNode 兄弟のセット全体における現在の exampleNode の位置になることに注意してください。これは、$counter 変数を使用してインデックスをテストするフィルターを渡す exampleNodes を「コピー」する中間変数を使用することで修正できます。
  3. あなたのスニペット

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

    おそらくいくつかの混乱が見逃されていますが、typeOfnode iso AgreementType のことですか? :D

それはさておき、もっと簡単な解決策があります。たとえば、非常に直接的です:

<xsl:value-of select="sum(exampleNode[@typeOfnode='1']/@amount)"/>
于 2012-05-31T17:28:28.070 に答える
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

本当に、本当に再帰的なソリューションが必要な場合

<?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 リストとより高いアキュムレータを使用して再帰部分を呼び出します。これにより、再帰がある時点で停止することが保証されます。

しかし、より簡単な解決策については、私の他の回答を参照してください...

于 2012-05-31T18:11:17.207 に答える