XSL、SUM 和与条件相乘
XSL, SUM & Multiply with Condition
我正在为大学做作业(所以我是 XSL 编码的新手)制作一个准电子商务网站,我会提供尽可能多的细节,以便它有意义。
样本XML数据:
<Items>
<Item>
<ItemID>50001</ItemID>
<ItemName>Samsung Galaxy S4</ItemName>
<ItemPrice>629</ItemPrice>
<ItemQty>14</ItemQty>
<ItemDesc>4G Mobile</ItemDesc>
<QtyHold>0</QtyHold>
<QtySold>1</QtySold>
</Item>
<Item>
<ItemID>50002</ItemID>
<ItemName>Samsung Galaxy S5</ItemName>
<ItemPrice>779</ItemPrice>
<ItemQty>21</ItemQty>
<ItemDesc>4G Mobile</ItemDesc>
<QtyHold>0</QtyHold>
<QtySold>1</QtySold>
</Item>
</Items>
所以这个过程是,当一个人点击顶部Table中的'Add to Cart'时,XML中的ItemQty上的ItemQty减1,同时它增加1在 QtyHold 中 XML。 (QtyHold 表示已添加到购物车的商品。因此,如果 QtyHold >0,则表示已添加到购物车)
我的问题涉及第二个 Table(下面的代码),其中总数字有效 - 仅当处理 1 个项目时。因此,如果第 2 次添加项目编号“50001”,总计不会改变。
<xsl:template match="/">
<fieldset>
<legend>Shopping Cart</legend>
<BR />
<table border="1" id="CartTable" align="center">
<tr><th>Item Number</th>
<th>Price</th>
<th>Quantity</th>
<th>Remove</th></tr>
<xsl:for-each select="/Items/Item[QtyHold > 0]">
<tr><td><xsl:value-of select="ItemID"/></td>
<td>$<xsl:value-of select="ItemPrice"/></td>
<td><xsl:value-of select="QtyHold"/></td>
<td><button onclick="addtoCart({ItemID}, 'Remove')">Remove from Cart</button></td> </tr>
</xsl:for-each>
<tr><td ALIGN="center" COLSPAN="3">Total:</td><td>$<xsl:value-of select="sum(//Item[QtyHold >0]/ItemPrice)"/></td></tr>
</table>
<BR />
<button onclick="Purchase()" class="submit_btn float_l">Confirm Purchase</button>
<button onclick="CancelOrder()" class="submit_btn float_r">Cancel Order</button>
</fieldset>
</xsl:template>
</xsl:stylesheet>
所以需要在下面的代码中发生,当它检查 QtyHold 是否大于 0(这意味着它在购物车中)并且对这些值求和时,它还需要将 QtyHold 和 ItemPrice 相乘.
<xsl:value-of select="sum(//Item[QtyHold >0]/ItemPrice)"/>
我尝试了很多类似下面代码的变体...但似乎无法使任何工作正常进行。
select="sum(//Item[QtyHold >0]/ItemPrice)/(QtyHold*ItemPrice"/>
如果您使用的是 XSLT 2.0,您可以使用的表达式如下:
<xsl:value-of select="sum(//Item[QtyHold >0]/(ItemPrice * QtyHold))"/>
但是,在 XSLT 1.0 中这是不允许的。相反,您可以通过扩展功能获得所需的结果。特别是“node-set”函数。首先,您将创建一个这样的变量,在其中构建包含每个项目的新节点
<xsl:variable name="itemTotals">
<xsl:for-each select="//Item[QtyHold >0]">
<total>
<xsl:value-of select="ItemPrice * QtyHold" />
</total>
</xsl:for-each>
</xsl:variable>
理想情况下,你想做 sum($itemTotals/total)
,但这行不通,因为 itemTotals
是一个 "Result Tree Fragment" 而 sum
函数只接受一个节点-放。所以你使用节点集扩展函数来转换它。首先在您的 XSLT 中声明此命名空间...
xmlns:exsl="http://exslt.org/common"
那么,您的求和函数将如下所示:
<xsl:value-of select="sum(exsl:node-set($itemTotals)/total)"/>
或者,如果您甚至不能使用扩展函数,您可以使用 "following-sibling" 方法,一次 select 每个 Item
,并保留一个 运行总计。因此,您将拥有这样的模板:
<xsl:template match="Item" mode="sum">
<xsl:param name="runningTotal" select="0" />
<xsl:variable name="newTotal" select="$runningTotal + ItemPrice * QtyHold" />
<xsl:variable name="nextItem" select="following-sibling::Item[1]" />
<xsl:choose>
<xsl:when test="$nextItem">
<xsl:apply-templates select="$nextItem" mode="sum">
<xsl:with-param name="runningTotal" select="$newTotal" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$newTotal" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
要调用它,获取总和,您只需从 select 第一个节点开始
<xsl:apply-templates select="(//Item)[1]" mode="sum" />
试试这个演示了各种方法的 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
<xsl:output method="html" indent="yes" />
<xsl:template match="/">
<table border="1" id="CartTable" align="center">
<tr><th>Item Number</th>
<th>Price</th>
<th>Quantity</th>
</tr>
<xsl:for-each select="/Items/Item[QtyHold > 0]">
<tr>
<td><xsl:value-of select="ItemID"/></td>
<td>$<xsl:value-of select="ItemPrice"/></td>
<td><xsl:value-of select="QtyHold"/></td>
</tr>
</xsl:for-each>
<tr>
<td ALIGN="center" COLSPAN="2">Total:</td>
<xsl:variable name="itemTotals">
<xsl:for-each select="//Item[QtyHold >0]">
<total>
<xsl:value-of select="ItemPrice * QtyHold" />
</total>
</xsl:for-each>
</xsl:variable>
<td>
<!-- XSLT 2.0 only: $<xsl:value-of select="sum(//Item[QtyHold >0]/(ItemPrice * QtyHold))"/>-->
$<xsl:value-of select="sum(exsl:node-set($itemTotals)/total)"/>
$<xsl:apply-templates select="(//Item)[1]" mode="sum" />
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="Item" mode="sum">
<xsl:param name="runningTotal" select="0" />
<xsl:variable name="newTotal" select="$runningTotal + ItemPrice * QtyHold" />
<xsl:variable name="nextItem" select="following-sibling::Item[1]" />
<xsl:choose>
<xsl:when test="$nextItem">
<xsl:apply-templates select="$nextItem" mode="sum">
<xsl:with-param name="runningTotal" select="$newTotal" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$newTotal" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
作为最后的想法,为什么不为 XML 中的每个 Item
元素添加一个新的 Total
元素。最初,它将设置为 0,如 QtyHold
。然后,当您将 QtyHold
增加 1 时,通过您执行的任何过程,您也可以将 Total
增加 ItemPrice
中的数量。这样,您只需对 Total
节点求和即可得到总计,而无需扩展函数或递归模板。
我正在为大学做作业(所以我是 XSL 编码的新手)制作一个准电子商务网站,我会提供尽可能多的细节,以便它有意义。
样本XML数据:
<Items>
<Item>
<ItemID>50001</ItemID>
<ItemName>Samsung Galaxy S4</ItemName>
<ItemPrice>629</ItemPrice>
<ItemQty>14</ItemQty>
<ItemDesc>4G Mobile</ItemDesc>
<QtyHold>0</QtyHold>
<QtySold>1</QtySold>
</Item>
<Item>
<ItemID>50002</ItemID>
<ItemName>Samsung Galaxy S5</ItemName>
<ItemPrice>779</ItemPrice>
<ItemQty>21</ItemQty>
<ItemDesc>4G Mobile</ItemDesc>
<QtyHold>0</QtyHold>
<QtySold>1</QtySold>
</Item>
</Items>
所以这个过程是,当一个人点击顶部Table中的'Add to Cart'时,XML中的ItemQty上的ItemQty减1,同时它增加1在 QtyHold 中 XML。 (QtyHold 表示已添加到购物车的商品。因此,如果 QtyHold >0,则表示已添加到购物车)
我的问题涉及第二个 Table(下面的代码),其中总数字有效 - 仅当处理 1 个项目时。因此,如果第 2 次添加项目编号“50001”,总计不会改变。
<xsl:template match="/">
<fieldset>
<legend>Shopping Cart</legend>
<BR />
<table border="1" id="CartTable" align="center">
<tr><th>Item Number</th>
<th>Price</th>
<th>Quantity</th>
<th>Remove</th></tr>
<xsl:for-each select="/Items/Item[QtyHold > 0]">
<tr><td><xsl:value-of select="ItemID"/></td>
<td>$<xsl:value-of select="ItemPrice"/></td>
<td><xsl:value-of select="QtyHold"/></td>
<td><button onclick="addtoCart({ItemID}, 'Remove')">Remove from Cart</button></td> </tr>
</xsl:for-each>
<tr><td ALIGN="center" COLSPAN="3">Total:</td><td>$<xsl:value-of select="sum(//Item[QtyHold >0]/ItemPrice)"/></td></tr>
</table>
<BR />
<button onclick="Purchase()" class="submit_btn float_l">Confirm Purchase</button>
<button onclick="CancelOrder()" class="submit_btn float_r">Cancel Order</button>
</fieldset>
</xsl:template>
</xsl:stylesheet>
所以需要在下面的代码中发生,当它检查 QtyHold 是否大于 0(这意味着它在购物车中)并且对这些值求和时,它还需要将 QtyHold 和 ItemPrice 相乘.
<xsl:value-of select="sum(//Item[QtyHold >0]/ItemPrice)"/>
我尝试了很多类似下面代码的变体...但似乎无法使任何工作正常进行。
select="sum(//Item[QtyHold >0]/ItemPrice)/(QtyHold*ItemPrice"/>
如果您使用的是 XSLT 2.0,您可以使用的表达式如下:
<xsl:value-of select="sum(//Item[QtyHold >0]/(ItemPrice * QtyHold))"/>
但是,在 XSLT 1.0 中这是不允许的。相反,您可以通过扩展功能获得所需的结果。特别是“node-set”函数。首先,您将创建一个这样的变量,在其中构建包含每个项目的新节点
<xsl:variable name="itemTotals">
<xsl:for-each select="//Item[QtyHold >0]">
<total>
<xsl:value-of select="ItemPrice * QtyHold" />
</total>
</xsl:for-each>
</xsl:variable>
理想情况下,你想做 sum($itemTotals/total)
,但这行不通,因为 itemTotals
是一个 "Result Tree Fragment" 而 sum
函数只接受一个节点-放。所以你使用节点集扩展函数来转换它。首先在您的 XSLT 中声明此命名空间...
xmlns:exsl="http://exslt.org/common"
那么,您的求和函数将如下所示:
<xsl:value-of select="sum(exsl:node-set($itemTotals)/total)"/>
或者,如果您甚至不能使用扩展函数,您可以使用 "following-sibling" 方法,一次 select 每个 Item
,并保留一个 运行总计。因此,您将拥有这样的模板:
<xsl:template match="Item" mode="sum">
<xsl:param name="runningTotal" select="0" />
<xsl:variable name="newTotal" select="$runningTotal + ItemPrice * QtyHold" />
<xsl:variable name="nextItem" select="following-sibling::Item[1]" />
<xsl:choose>
<xsl:when test="$nextItem">
<xsl:apply-templates select="$nextItem" mode="sum">
<xsl:with-param name="runningTotal" select="$newTotal" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$newTotal" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
要调用它,获取总和,您只需从 select 第一个节点开始
<xsl:apply-templates select="(//Item)[1]" mode="sum" />
试试这个演示了各种方法的 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
<xsl:output method="html" indent="yes" />
<xsl:template match="/">
<table border="1" id="CartTable" align="center">
<tr><th>Item Number</th>
<th>Price</th>
<th>Quantity</th>
</tr>
<xsl:for-each select="/Items/Item[QtyHold > 0]">
<tr>
<td><xsl:value-of select="ItemID"/></td>
<td>$<xsl:value-of select="ItemPrice"/></td>
<td><xsl:value-of select="QtyHold"/></td>
</tr>
</xsl:for-each>
<tr>
<td ALIGN="center" COLSPAN="2">Total:</td>
<xsl:variable name="itemTotals">
<xsl:for-each select="//Item[QtyHold >0]">
<total>
<xsl:value-of select="ItemPrice * QtyHold" />
</total>
</xsl:for-each>
</xsl:variable>
<td>
<!-- XSLT 2.0 only: $<xsl:value-of select="sum(//Item[QtyHold >0]/(ItemPrice * QtyHold))"/>-->
$<xsl:value-of select="sum(exsl:node-set($itemTotals)/total)"/>
$<xsl:apply-templates select="(//Item)[1]" mode="sum" />
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="Item" mode="sum">
<xsl:param name="runningTotal" select="0" />
<xsl:variable name="newTotal" select="$runningTotal + ItemPrice * QtyHold" />
<xsl:variable name="nextItem" select="following-sibling::Item[1]" />
<xsl:choose>
<xsl:when test="$nextItem">
<xsl:apply-templates select="$nextItem" mode="sum">
<xsl:with-param name="runningTotal" select="$newTotal" />
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$newTotal" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
作为最后的想法,为什么不为 XML 中的每个 Item
元素添加一个新的 Total
元素。最初,它将设置为 0,如 QtyHold
。然后,当您将 QtyHold
增加 1 时,通过您执行的任何过程,您也可以将 Total
增加 ItemPrice
中的数量。这样,您只需对 Total
节点求和即可得到总计,而无需扩展函数或递归模板。