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
次の点に注意してください。
このf:zipWith()
関数は、fun()
(2つの引数の)関数と同じ長さのアイテムの2つのリストを引数として取ります。fun()
これは、同じ長さの新しいリストを生成します。そのアイテムは、2つのリストの対応するk
-番目のアイテムのペアワイズアプリケーションの結果です。
f:zipWith()
式のように、関数と、対応する" "および" "属性f:multiply()
の2つのシーケンスを取ります。結果はシーケンスであり、各アイテムは対応する「」と「」の積です。ammount
rate
ammount
rate
最後に、このシーケンスの合計が生成されます。
明示的な再帰を記述する必要はありません。また、内部で使用される舞台裏の再帰f:zipWith()
が「スタックオーバーフロー」でクラッシュすることはありません(すべての実用的なケースで)。