XSL - Get SUM of price

2019-02-16 02:19发布

问题:

I have a xml structure like:

<PartsDetail> <Id>1481</Id> <Desc>test1</Desc> <GlobDesc>test2</GlobDesc> <Price Cur="UAH">+798.27</Price> </PartsDetail> 
<PartsDetail> <Id>0741</Id> <Desc>test2</Desc> <GlobDesc>test2</GlobDesc> <Price Cur="UAH">+399.14</Price> </PartsDetail> 

And in view, I make some transformation with "price" (I bring to view like 399.14).

I use this for transformation:

<xsl:call-template name="showNumberWithThousands">
 <xsl:with-param name="value">
 <xsl:call-template name="parseNumber">
<xsl:with-param name="value" select="Price"/>
</xsl:call-template>
 </xsl:with-param>
 </xsl:call-template>

Also I need to take a sum of price now. I tried to use this:

<xsl:value-of select="sum(//Data/Paint//PartsDetail/@Price)"/>

But the a result is - NaN.

As I understand I need to transform the price in "normal view (without + and -)" before a send it to function "sum".

To: @michael.hor257k

Structure is more complicated. I use your solution - but it didn't work. It looks like I'm doing something wrong

<xsl:template name="PaintSum"> 
<xsl:variable name="corrected-prices"> 
<xsl:for-each select="//CalcData/Paint/PaintDtl"> 
<price> <xsl:value-of select="translate(MatAmnt, '+', '')"/> </price> 
</xsl:for-each> 
</xsl:variable> 
<sum> <xsl:value-of select="sum(exsl:node-set($corrected-prices)/price)"/> </sum>
</xsl:template> 

And when I use <xsl:call-template name="PaintSum"/> Nothing happens. Similarly, further request into templates stop working.

I'm trying to use:

<xsl:variable name="corrected-prices">
        <xsl:for-each select="//CalcData/Paint//PaintDtl">
            <price>
                <xsl:value-of select="translate(MatAmnt, '+', '')"/>
            </price>
        </xsl:for-each>
    </xsl:variable>

And add sum in text by :

<xsl:value-of select="sum(exsl:node-set($corrected-prices)/price)"/>

But output file - crashes.

$corrected-prices contains "1086.65286.75".

How can I turn this into a sum?

回答1:

As I understand I need transform price to "normal view (without + and -)" before a send it to function "sum".

That is more or less correct (you don't want to remove the minus sign, in case the number is negative). Given a well-formed input such as:

XML

<root>
  <PartsDetail>
    <Id>1481</Id>
    <Desc>test1</Desc>
    <GlobDesc>test2</GlobDesc>
    <Price Cur="UAH">+798.27</Price>
  </PartsDetail>
  <PartsDetail>
    <Id>0741</Id>
    <Desc>test2</Desc>
    <GlobDesc>test2</GlobDesc>
    <Price Cur="UAH">+399.14</Price>
  </PartsDetail>
</root>

the following stylesheet:

XSLT 1.0

<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:template match="/root">
    <xsl:variable name="corrected-prices">
        <xsl:for-each select="PartsDetail">
            <price>
                <xsl:value-of select="translate(Price, '+', '')"/>
            </price>
        </xsl:for-each>
    </xsl:variable>
    <sum>
        <xsl:value-of select="sum(exsl:node-set($corrected-prices)/price)"/>
    </sum>
</xsl:template>

</xsl:stylesheet>

will return:

<?xml version="1.0" encoding="UTF-8"?>
<sum>1197.41</sum>


回答2:

This transformation doesn't require the use of any extension functions and doesn't produce an intermediary tree -- in fact it runs with 0 additional memory and is suitable for streaming, if the XSLT processor recognizes tail-recursion:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
   <xsl:apply-templates select="(*/Price/text())[1]">
     <xsl:with-param name="pNodes" select="*/Price/text()"/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="text()" name="sum">
  <xsl:param name="pTotal" select="0"/>
  <xsl:param name="pNodes"/>
  <xsl:param name="pNode1" select="translate($pNodes[1],'+','')"/>

  <xsl:value-of select="substring($pTotal+$pNode1, 1 div not($pNodes[2]))"/>
  <xsl:apply-templates select="$pNodes[2][$pNode1]">
    <xsl:with-param name="pTotal" select="$pTotal+$pNode1"/>
    <xsl:with-param name="pNodes" select="$pNodes[position()>1]"/>
  </xsl:apply-templates>
 </xsl:template>
</xsl:stylesheet>

When it is applied on the provided XML document:

<root>
  <PartsDetail>
    <Id>1481</Id>
    <Desc>test1</Desc>
    <GlobDesc>test2</GlobDesc>
    <Price Cur="UAH">+798.27</Price>
  </PartsDetail>
  <PartsDetail>
    <Id>0741</Id>
    <Desc>test2</Desc>
    <GlobDesc>test2</GlobDesc>
    <Price Cur="UAH">+399.14</Price>
  </PartsDetail>
</root>

The wanted, correct result is produced:

1187.4099999999998


标签: php xml xslt sum