6

私は次のXMLソース構造を持っています:

<turnovers>
    <turnover repid="1" amount="500" rate="0.1"/>
    <turnover repid="5" amount="600" rate="0.5"/>
    <turnover repid="4" amount="400" rate="0.2"/>
    <turnover repid="1" amount="700" rate="0.05"/>
    <turnover repid="2" amount="100" rate="0.15"/>
    <turnover repid="1" amount="900" rate="0.25"/>
    <turnover repid="2" amount="1000" rate="0.18"/>
    <turnover repid="5" amount="200" rate="0.55"/>
    <turnover repid="9" amount="700" rate="0.40"/>
</turnovers>

指定された担当者IDのrate属性とamount属性の積の合計を返すXSL:value-ofselectステートメントが必要です。したがって、担当者5の場合、((600 x 0.5)+(200 x 0.55))が必要です。

4

6 に答える 6

9
<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="/turnovers">
    <val>
      <!-- call the sum function (with the relevant nodes) -->
      <xsl:call-template name="sum">
        <xsl:with-param name="nodes" select="turnover[@repid='5']" />
      </xsl:call-template>
    </val>
  </xsl:template>

  <xsl:template name="sum">  
    <xsl:param name="nodes" />
    <xsl:param name="sum" select="0" />

    <xsl:variable name="curr" select="$nodes[1]" />

    <!-- if we have a node, calculate & recurse -->
    <xsl:if test="$curr">
      <xsl:variable name="runningsum" select="
        $sum + $curr/@amount * $curr/@rate
      " />
      <xsl:call-template name="sum">
        <xsl:with-param name="nodes" select="$nodes[position() &gt; 1]" />
        <xsl:with-param name="sum"   select="$runningsum" />
      </xsl:call-template>
    </xsl:if>

    <!-- if we don't have a node (last recursive step), return sum -->
    <xsl:if test="not($curr)">
      <xsl:value-of select="$sum" />
    </xsl:if>

  </xsl:template>
</xsl:stylesheet>

与える:

<val>410</val>

2<xsl:if>つのは1つのに置き換えることができます<xsl:choose>。これは、再帰中のチェックが1つ少なくなることを意味しますが、コードが2行追加されることも意味します。

于 2009-08-26T12:56:14.853 に答える
2

プレーンなXSLT1.0では、このための再帰的なテンプレートが必要です。次に例を示します。

  <xsl:template match="turnovers">
    <xsl:variable name="selectedId" select="5" />
    <xsl:call-template name="sum_turnover">
      <xsl:with-param name="turnovers" select="turnover[@repid=$selectedId]" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="sum_turnover">
    <xsl:param name="total" select="0" />
    <xsl:param name="turnovers"  />
    <xsl:variable name="head" select="$turnovers[1]" />
    <xsl:variable name="tail" select="$turnovers[position()>1]" />
    <xsl:variable name="calc" select="$head/@amount * $head/@rate" />
    <xsl:choose>
      <xsl:when test="not($tail)">
        <xsl:value-of select="$total + $calc" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="sum_turnover">
          <xsl:with-param name="total" select="$total + $calc" />
          <xsl:with-param name="turnovers" select="$tail" />
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
于 2009-08-26T11:48:58.193 に答える
1

これでうまくいくはずです。別repidのを選択するには、さらに作業を行う必要があります。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">    
        <xsl:variable name="totals">
            <product>
                <xsl:for-each select="turnovers/turnover">
                    <repid repid="{@repid}">
                        <value><xsl:value-of select="@amount * @rate"/></value>
                    </repid>
                </xsl:for-each>
            </product>
        </xsl:variable>
        <totals>
            <total repid="5" value="{sum($totals/product/repid[@repid='5']/value)}"/>   
        </totals>               
    </xsl:template>

</xsl:stylesheet>
于 2009-08-26T11:19:53.527 に答える
1

XSLT 1.0では、FXSLを使用すると、このような問題を簡単に解決できます。

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:f="http://fxsl.sf.net/"
 xmlns:ext="http://exslt.org/common"
 exclude-result-prefixes="xsl f ext"
 >
 <xsl:import href="zipWith.xsl"/>
 <xsl:output method="text"/>

  <xsl:variable name="vMultFun" select="document('')/*/f:mult-func[1]"/>    

    <xsl:template match="/"> 
      <xsl:call-template name="profitForId"/>
    </xsl:template>

    <xsl:template name="profitForId">
      <xsl:param name="pId" select="1"/>

      <xsl:variable name="vrtfProducts">
          <xsl:call-template name="zipWith">
            <xsl:with-param name="pFun" select="$vMultFun"/>
            <xsl:with-param name="pList1" select="/*/*[@repid = $pId]/@amount"/>
            <xsl:with-param name="pList2" select="/*/*[@repid = $pId]/@rate"/>
          </xsl:call-template>
      </xsl:variable>

      <xsl:value-of select="sum(ext:node-set($vrtfProducts)/*)"/>
    </xsl:template>

    <f:mult-func/>
    <xsl:template match="f:mult-func" mode="f:FXSL">
     <xsl:param name="pArg1"/>
     <xsl:param name="pArg2"/>

     <xsl:value-of select="$pArg1 * $pArg2"/>
    </xsl:template>
</xsl:stylesheet>

この変換が最初に投稿されたソースXMLドキュメントに適用されると、正しい結果が生成されます。

310

XSLT 2.0では、FXSL2.0を使用した同じソリューションをXPathワンライナーで表現できます。

sum(f:zipWith(f:multiply(),
          /*/*[xs:decimal(@repid) eq 1]/@amount/xs:decimal(.),
          /*/*[xs:decimal(@repid) eq 1]/@rate/xs:decimal(.)
          )
     )

全体の変革:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:f="http://fxsl.sf.net/"
 exclude-result-prefixes="f xs"
>
 <xsl:import href="../f/func-zipWithDVC.xsl"/>
 <xsl:import href="../f/func-Operators.xsl"/>

 <!-- To be applied on testFunc-zipWith4.xml -->
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
   <xsl:value-of select=
   "sum(f:zipWith(f:multiply(),
              /*/*[xs:decimal(@repid) eq 1]/@amount/xs:decimal(.),
              /*/*[xs:decimal(@repid) eq 1]/@rate/xs:decimal(.)
              )
         )
    "/>
 </xsl:template>
</xsl:stylesheet>

繰り返しますが、この変換は正しい答えを生成します。

310

次の点に注意してください

  1. このf:zipWith()関数は、fun()(2つの引数の)関数と同じ長さのアイテムの2つのリストを引数として取ります。fun()これは、同じ長さの新しいリストを生成します。そのアイテムは、2つのリストの対応するk-番目のアイテムのペアワイズアプリケーションの結果です。

  2. f:zipWith()式のように、関数と、対応する" "および" "属性f:multiply()の2つのシーケンスを取ります。結果はシーケンスであり、各アイテムは対応する「」と「」の積です。ammountrateammountrate

  3. 最後に、このシーケンスの合計が生成されます。

  4. 明示的な再帰を記述する必要はありません。また、内部で使用される舞台裏の再帰f:zipWith()が「スタックオーバーフロー」でクラッシュすることはありません(すべての実用的なケースで)。

于 2009-08-26T14:12:55.290 に答える
0
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      exclude-result-prefixes="xs"
      version="2.0">

   <xsl:variable name="repid" select="5" />

   <xsl:template match="/">
      <xsl:value-of select=
         "sum(for $x in /turnovers/turnover[@repid=$repid] return $x/@amount * $x/@rate)"/>
   </xsl:template>

</xsl:stylesheet>

xmlではなく値だけが必要な場合は、これを行うことができます。

于 2009-11-25T22:38:14.857 に答える
-2

XSLTでこれを行う最も簡単な方法は、プログラミング言語のバインディングを使用して、独自のXPath関数を定義できるようにすることです。

于 2009-08-26T10:16:35.540 に答える