Summing numbers with comma as decimal separator in XSLT?

前端 未结 3 1684
时光取名叫无心
时光取名叫无心 2020-12-04 00:41

I have an XML file where the number are comma-separated


  
  
  


        
相关标签:
3条回答
  • 2020-12-04 01:22

    Assuming the same as Dimitre, that you mean that comma is used as a decimal separator, not as a separator for list of integers.

    Pure XSLT 1.0 without EXSLT node-set extension:

    <xsl:template match="foo">
      <xsl:call-template name="sum">
        <xsl:with-param name="node" select="bar[1]"/>
      </xsl:call-template>
    </xsl:template>
    
    <xsl:template name="sum">
      <xsl:param name="node"/>
      <xsl:param name="sum" select="0"/>
      <xsl:choose>
        <xsl:when test="$node">
          <xsl:call-template name="sum">
            <xsl:with-param name="node" select="$node/following-sibling::bar[1]"/>
            <xsl:with-param name="sum" select="$sum + translate($node/@val, ',', '.')"/>
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$sum"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>
    
    0 讨论(0)
  • 2020-12-04 01:24

    I feel like I say this a lot, but it bears repeating: the whole point of XML is that it provides data in an easily parsable form. XML that contains data that can't be parsed as XML makes no sense; if at all possible, you should either fix your XML or use a different format.

    0 讨论(0)
  • 2020-12-04 01:39

    I am guessing, that the value specified in a "val" attribute is a number that has comma instead of a decimal point.

    Several solutions are possible:

    I. XSLT 1.0

    This transformation:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:ext="http://exslt.org/common"
     >
      <xsl:output method="text"/>
    <!--                                           -->  
        <xsl:template match="foo">
          <xsl:variable name="vrtfBars">
            <xsl:for-each select="bar">
              <bar val="{translate(@val, ',', '.')}"/>
            </xsl:for-each>
          </xsl:variable>
    <!--                                           -->
          <xsl:value-of select=
           "sum(ext:node-set($vrtfBars)/*/@val)"/>
        </xsl:template>
    </xsl:stylesheet>
    

    when applied on the originally-provided XML document:

    <foo>
        <bar val="1,23"/>
        <bar val="4,56"/>
        <bar val="7,89"/>
    </foo>
    

    produces the wanted result:

    13.68
    

    II. XSLT 2.0

    This transformation:

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     exclude-result-prefixes="f xs"
     >
     <xsl:output method="text"/>
    <!--                                           -->
     <xsl:template match="foo">
      <xsl:sequence select=
       "sum(bar/@val/number(translate(., ',', '.')))" 
       />
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on the same XML document, produces the same correct result:

    13.68

    III. FXSL 2.x

    This transformation:

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns:f="http://fxsl.sf.net/"
     xmlns:my="my:fun"
     exclude-result-prefixes="my f xs"
     >
       <xsl:import href="../f/func-transform-and-sum.xsl"/>
    <!--                                           -->
     <xsl:output method="text"/>
    <!--                                           -->
     <xsl:template match="foo">
      <xsl:sequence select=
       "sum(
            f:transform-and-sum(my:makeNum(), bar/@val )
            )" 
       />
     </xsl:template>
    <!--                                           -->
     <xsl:function name="my:makeNum" as="xs:double">
       <xsl:param name="psNum" as="xs:string"/>
    <!--                                           -->
       <xsl:sequence select="number(translate($psNum, ',', '.'))"/>
     </xsl:function>
    <!--                                           -->
     <xsl:function name="my:makeNum" as="element()">
       <my:makeNum/>
     </xsl:function>
    <!--                                           -->
     <xsl:template match="my:makeNum" as="xs:double" mode="f:FXSL">
       <xsl:param name="arg1" as="xs:string"/>
    <!--                                           -->
       <xsl:sequence select="my:makeNum($arg1)"/>
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on the same XML document produces the same correct result:

    13.68

    The last solution is more flexible and can be used successfully when a more complex transformation of the values is needed before summing.

    0 讨论(0)
提交回复
热议问题