【问题标题】:XSL, SUM & Multiply with ConditionXSL、SUM 和条件乘法
【发布时间】:2015-10-23 13:11:54
【问题描述】:

我正在为大学做作业(所以我是 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>

Website

所以过程是,当一个人点击顶部表中的“添加到购物车”时,XML 中的 ItemQty 中的 ItemQty 减 1,而 XML 中的 QtyHold 中的 ItemQty 增加 1。 (QtyHold 表示已添加到购物车中的内容。因此,如果 QtyHold 大于 0,则将其添加到购物车中)

我的问题是指第二个表(下面的代码),其中 Total 数字起作用 - 仅在处理 1 个项目时。因此,如果第二次添加项目编号“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 sum value-of


    【解决方案1】:

    如果您使用的是 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 是“结果树片段”,而sum 函数只接受节点集。所以你使用节点集扩展函数来转换它。首先在你的 XSLT 中声明这个命名空间...

     xmlns:exsl="http://exslt.org/common"
    

    那么,你的 sum 函数将如下所示:

     <xsl:value-of select="sum(exsl:node-set($itemTotals)/total)"/>
    

    或者,如果您甚至不能使用扩展功能,您可以使用“following-sibling”方法,一次选择每个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>
    

    要调用它,要得到总和,您只需从选择第一个节点开始

    <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 节点求和即可获得总和,而无需扩展函数或递归模板。

    【讨论】:

    • 非常感谢 Tim C... 现在一切正常! :-) 我本来想在 XML 文件中添加一个运行总计,但是在作业文件中指定了 xml 应该包含哪些数据。而且...如果我们在做 XSLT 2.0,我几乎走在了正确的道路上,但我们的讲师似乎一直坚持教授“遗留”作为一个想法,我们的 Javascript 文件必须包括对使用 ActiveX 的 IE 的支持。支持 AJAX 调用。 (所以我们必须建立支持 IE4,5 & 6 的网站)
    • 很好的答案.. 谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多