【问题标题】:XSL how to calculate the sum of the product of the attribute values of each elementXSL如何计算每个元素的属性值的乘积之和
【发布时间】:2014-01-27 10:20:55
【问题描述】:

我有这个 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 映射器 11.1.1.6.0(内部版本 111214.0600.1553)生成
  • 样式表版本="1.0"

两天以来我做了很多研究并使用了一些模板 获得totalAmount,但它适用于浏览器测试器,但不适用于“jdeveloper”转换。 我发现问题出在模板匹配上

在浏览器 &lt;xsl:template match="/Process/ListOfItems"&gt; 中工作但在 jdev 中没有 即使&lt;xsl:template match="/"&gt; 也不起作用

请帮忙解决这个问题,

提前致谢。

【问题讨论】:

  • 你能告诉我们你尝试了什么吗?
  • 正如许多人所指出的,XSLT 1.0 和 2.0 的解决方案完全不同,因此您确实应该通过说明您使用的是哪个版本来节省人们的时间。

标签: xml xslt


【解决方案1】:

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 中的 cmets 能够帮助您...

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      我也会使用 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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-09
        • 1970-01-01
        • 2017-01-12
        • 1970-01-01
        相关资源
        最近更新 更多