0

Im doing an assignment for University (so im new to XSL coding) in making a quasi ecommerce site, and will provide as much detail as i can so it makes sense.

Sample XML Data:

<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

So the process is, when a person clicks 'Add to Cart' in the top Table, the ItemQty is decreased by 1 on the ItemQty in the XML, while it increases by 1 in the QtyHold in the XML. (QtyHold represents what has been added to the shopping Cart. Thus if QtyHold is >0 then its been added to the Cart)

My problem refers to the 2nd Table (code below), where the Total figure works - only if dealing with 1 Item. Thus, if Item Number '50001' is added a 2nd time, the Total wont change.

<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>

So what needs to happen is within the following code, while it checks if the QtyHold is greater than 0 (which would mean its in the shopping Cart) & to sum these values, it also needs to multiply QtyHold & ItemPrice.

<xsl:value-of select="sum(//Item[QtyHold >0]/ItemPrice)"/>

I tried many variations of Code like this below... but can't seem to make anything work.

select="sum(//Item[QtyHold >0]/ItemPrice)/(QtyHold*ItemPrice"/>
4

1 回答 1

2

如果您使用的是 XSLT 2.0,您可以使用的表达式如下:

<xsl:value-of select="sum(//Item[QtyHold >0]/(ItemPrice * QtyHold))"/>

但是,在 XSLT 1.0 中这是不允许的。相反,您可以使用扩展功能获得所需的结果。特别是“节点集”功能。首先,您将创建一个像这样的变量,在其中构造新节点来保存每个项目的总数

<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 中的Total每个元素添加一个新元素。Item最初,它将被设置为 0,如QtyHold. 然后,当您增加QtyHold1 时,无论您执行什么过程,您也可以Total增加ItemPrice. 这样,您只需对该Total节点求和即可获得总和,而无需扩展函数或递归模板。

于 2015-10-24T10:22:17.087 回答