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

问题描述 投票:0回答:3
xml xslt xslt-1.0
3个回答
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
投票

另一个使用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>

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"/>
        <!-- pre-process items -->
        <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>
        <xsl:variable name="total" select="sum(exsl:node-set($items)/item/@value)" />
        <!-- output -->
        <ListOfItems>
            <xsl:copy-of select="$items"/>
        </ListOfItems>
        <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>

如果你的处理器恰好支持EXSLT dyn:map() 扩展函数,那么你还有另一种方法可以得到预期的结果:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="dyn">
<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"/>
        <ListOfItems>
            <xsl:for-each select="ListOfItems/item">
                <xsl:copy>
                    <xsl:copy-of select="@*"/>
                    <xsl:attribute name="extprice">
                        <xsl:value-of select="@price * @quantity" />
                    </xsl:attribute>
                </xsl:copy>
            </xsl:for-each>
        </ListOfItems>
        <xsl:variable name="total" select="sum(dyn:map(ListOfItems/item, '@price * @quantity'))" />
        <total>
            <xsl:value-of select="$total" />
        </total>
        <tax>
            <xsl:value-of select="$total * $taxRate" />
        </tax>
        <grandTotal>
            <xsl:value-of select="$total * (1 + $taxRate)" />
        </grandTotal>
    </ProcessResponse>
</xsl:template>

</xsl:stylesheet>
© www.soinside.com 2019 - 2024. All rights reserved.