XSL如何计算每个元素的属性值的乘积之和

时间:2014-01-27 10:20:55

标签: xml xslt

我有这个xml

<Process>
    <name>name1</name>
    <ListOfItems>
        <item name="name2" price="10" quantity="1" value=""></item>
        <item name="name7" price="10" quantity="2" value=""></item>
        <item name="name12" price="10" quantity="3" value=""></item>
        <item name="name17" price="10" quantity="4" value=""></item>
    </ListOfItems>
    <taxType>TEN</taxType>
</Process>

我希望输出

<ProcessResponse>
    <name>name1</name>
    <ListOfItems>
        <item name="name2" price="10" quantity="1" value="10"></item>
        <item name="name7" price="10" quantity="2" value="20"></item>
        <item name="name12" price="10" quantity="3" value="30"></item>
        <item name="name17" price="10" quantity="4" value="40"></item>
    </ListOfItems>
    <totalAmount>100</totalAmount>
    <taxAmount>10</taxAmount>
    <grandTotal>110</grandTotal>
</ProcessResponse>

它的发票目的,一些额外的信息:

  • value是商品成本(价格x数量)
  • totalAmount是sum(value)
  • taxAmount是(如果taxType = AAA,taxAmount = totalAmount x(某个固定数字/ 100))
  • 最后是grandTotal = totalAmount + taxAmount
  • 由ORACLE XSL MAPPER生成11.1.1.6.0(build 111214.0600.1553)
  • stylesheet version =“1.0”

我从2天开始做了很多研究,并使用了一些模板 获取totalAmount但它在浏览器测试器上工作但在“jdeveloper”转换中没有。 我知道问题出在模板匹配

浏览器<xsl:template match="/Process/ListOfItems">中的

工作但不在jdev中 即使<xsl:template match="/">无效

请帮助解决这个问题,

提前致谢。

3 个答案:

答案 0 :(得分:2)

XSLT 2.0内,计算值的sum()要容易得多,但在XSLT 1.0内它有点棘手,请参阅下一个XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <!-- Identity template -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <!-- Rename root node -->
    <xsl:template match="Process">
        <ProcessResponse>
            <xsl:apply-templates select="@*|node()" />
        </ProcessResponse>
    </xsl:template>

    <!-- Match on ListOfItems, to add new elements after it -->
    <xsl:template match="ListOfItems">
        <!-- Copy existing -->
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>

        <!-- Create the new elements -->
        <xsl:apply-templates select="item[1]" mode="sumValue" />
    </xsl:template>

    <!-- Match on item element to do the calculation of value attribute -->
    <xsl:template match="item">
        <xsl:copy>
            <!-- Copy existing attributes -->
            <xsl:apply-templates select="@*" />

            <!-- Actual calculation -->
            <xsl:attribute name="value">
                <xsl:value-of select="@quantity * @price" />
            </xsl:attribute>

            <!-- Copy rest of nodes -->
            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="item" mode="sumValue">
        <xsl:param name="currentSumValue" select="0" />

        <!-- Variable to store the updated sum value -->
        <xsl:variable name="updatedSumValue" select="$currentSumValue + (@quantity * @price)" />

        <!-- Proceed summing with the next item-->
        <xsl:apply-templates select="following-sibling::item[1]" mode="sumValue">
            <xsl:with-param name="currentSumValue" select="$updatedSumValue" />
        </xsl:apply-templates>

        <!-- No more items. Summing is complete, we can display the totalAmount and calculate the rest -->
        <xsl:if test="not(following-sibling::item)">
            <totalAmount><xsl:value-of select="$updatedSumValue"/></totalAmount>

            <!-- taxAmount -->
            <xsl:variable name="taxAmount">
                <xsl:choose>
                    <xsl:when test="/Process/taxType = 'TEN'">
                        <xsl:value-of select="$updatedSumValue * (10 div 100)" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$updatedSumValue" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <taxAmount><xsl:value-of select="$taxAmount" /></taxAmount>

            <!-- grandTotal -->
            <grandTotal><xsl:value-of select="$updatedSumValue + $taxAmount" /></grandTotal>
        </xsl:if>
    </xsl:template>

    <!-- Remove element taxType -->
    <xsl:template match="taxType" />
</xsl:stylesheet>

在输入XML上应用时,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<ProcessResponse>
    <name>name1</name>
    <ListOfItems>
        <item name="name2" price="10" quantity="1" value="10"/>
        <item name="name7" price="10" quantity="2" value="20"/>
        <item name="name12" price="10" quantity="3" value="30"/>
        <item name="name17" price="10" quantity="4" value="40"/>
    </ListOfItems>
    <totalAmount>100</totalAmount>
    <taxAmount>10</taxAmount>
    <grandTotal>110</grandTotal>
</ProcessResponse>

希望它有所帮助,并且de XSLT中的评论可以帮助您...

答案 1 :(得分:1)

使用XSLT 1.0的另一个版本,但它使用扩展函数

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ext="http://exslt.org/common"
    exclude-result-prefixes="ext"
    version="1.0">

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

<xsl:variable name="tmpvalue">
    <xsl:for-each select="//item">
        <value><xsl:value-of select="@price*@quantity"/></value>
    </xsl:for-each>
</xsl:variable>

<xsl:variable name="taxAmount">
    <!-- set you tax formula here -->
    <xsl:value-of select="'10'"/>
</xsl:variable>

    <xsl:template match="Process">
        <ProcessResponse>
            <xsl:apply-templates/>
            <totalAmount>
                <xsl:variable name="myValue" select="ext:node-set($tmpvalue)"/>
                <xsl:value-of select="sum($myValue/value)"/>
            </totalAmount>
            <taxAmount><xsl:value-of select="$taxAmount"/></taxAmount>
            <grandTotal>
                <xsl:variable name="myValue" select="ext:node-set($tmpvalue)"/>
                <xsl:value-of select="sum($myValue/value) + $taxAmount"/>
            </grandTotal>
        </ProcessResponse>
    </xsl:template>

    <xsl:template match="item">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="value"><xsl:value-of select="@price*@quantity"/></xsl:attribute>
        </xsl:copy>

    </xsl:template>

</xsl:stylesheet>

答案 2 :(得分:1)

我也会使用EXSLT node-set()函数,只使用较少的模板:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:param name="taxRate" select=".06"/>

<xsl:template match="/Process">
<ProcessResponse>
    <xsl:copy-of select="name"/>

    <xsl:variable name="items">
        <xsl:for-each select="ListOfItems/item">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:attribute name="value">
                    <xsl:value-of select="@price*@quantity" />
                </xsl:attribute>
            </xsl:copy>
        </xsl:for-each>
    </xsl:variable>

    <ListOfItems>
        <xsl:copy-of select="$items"/>
    </ListOfItems>

    <xsl:variable name="total" select="sum(exsl:node-set($items)/item/@value)" />

    <totalAmount><xsl:value-of select="$total" /></totalAmount>
    <taxAmount><xsl:value-of select="$total*$taxRate" /></taxAmount>
    <grandTotal><xsl:value-of select="$total*(1 + $taxRate)" /></grandTotal>
</ProcessResponse>
</xsl:template>

</xsl:stylesheet>