How do I use SUM and AVERAGE in XSL?

2019-07-23 21:37发布

I want to the total kilometers per car and the average kilometers per day

This is the input XML :

 <?xml version="1.0" encoding="ISO-8859-1" ?>   

 <output>   
<cars>  
   <car>    
      <id>1</id>    
      <brand>BMW</brand>    
      <type>M3</type>   
      <license>AD-9999-ATSR</license>   
   </car>   
<car>   
     <id>2</id> 
     <brand>Volkwagen</brand>   
     <type>GTI</type>   
     <license>ASD-7458-WERT</license>   
     </car> 
 </cars>    
 <distances>    
  <distance>    
    <id_car>1</id_car>  
    <date>20120118</date>   
    <distance>90</distance> 
</distance> 
 <distance> 
  <id_car>1</id_car>    
  <date>20120117</date> 
  <distance>23</distance>   
  </distance>
 <distance> 
  <id_car>1</id_car>    
  <date>20120117</date> 
  <distance>17</distance>   
  </distance>
<distance>  
  <id_car>1</id_car>    
 <date>20120116</date>  
 <distance>5</distance> 
 </distance>    
 <distance> 
 <id_car>2</id_car> 
<date>20120101</date>   
 <distance>92</distance>    
</distance> 
 <distance> 
 <id_car>2</id_car> 
 <date>20120102</date>  
 <distance>87</distance>    
 </distance>
 <distance> 
 <id_car>2</id_car> 
 <date>20120102</date>  
 <distance>13</distance>    
 </distance>    
<distance>  
 <id_car>2</id_car> 
 <date>20120103</date>  
 <distance>112</distance>   
  </distance>   
 </distances>   
</output>   

This is the output xml :

<?xml version="1.0" encoding="ISO-8859-1" ?> 
<output>
<cars>
<car>
  <id>1</id>
  <brand>BMW</brand>
  <type>M3</type>
  <license>AD-9999-ATSR</license>
    <distance Total_kM="135"></distance>
    <distance average_KM/day="18/90"></distance>
    <distance average_KM/day="17/20"></distance>
    <distance average_KM/day="16/5"></distance>
</car>
<car>
  <id>2</id>
  <brand>Volkwagen</brand>
  <type>GTI</type>
  <license>ASD-7458-WERT</license>
    <distance Total_kM="304"></distance>
    <distance averageKM/day="01/90"></distance>
    <distance average_KM/day="02/50"></distance>
    <distance average_KM/day="03/112"></distance>
</car>
</cars>
</output>

Something like this or onother arangement you can think of ,in the output, to show the total kilometers per car and the average kilometers per day

This is the xsl that i am trying to change :

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="distances" match="distance" use="id_car" />

    <xsl:template match="output">
        <xsl:apply-templates select="cars" />
    </xsl:template>

    <xsl:template match="car">
        <xsl:copy>
            <xsl:apply-templates />
            <distances>
                <xsl:apply-templates select="key('distances', id)" />
            </distances>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="distance">
        <distance day="{date}">
            <xsl:value-of select="distance" />
        </distance>
    </xsl:template>

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

How do I use SUM and AVERAGE in XSL to ouput what i want ?

Thank you for your time and effort

标签: xslt xslt-1.0
1条回答
来,给爷笑一个
2楼-- · 2019-07-23 22:08

The following stylesheet produces the wanted result:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:key name="byCarId" match="distance" use="id_car"/>
    <xsl:key name="byCarIdAndDate" match="distance" 
             use="concat(id_car, '|', date)"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="car">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <distance Total_kM="{sum(key('byCarId', id)/distance)}"/>
            <xsl:apply-templates select="key('byCarId', id)"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template
        match="distance[generate-id()=
                        generate-id(key('byCarIdAndDate', 
                                        concat(id_car, '|', date))[1])]">
        <xsl:variable name="thisDate"
            select="key('byCarIdAndDate', concat(id_car, '|', date))"/>
        <xsl:variable name="sum" select="sum($thisDate/distance)"/>
        <xsl:variable name="count" select="count($thisDate)"/>
        <distance average_KM_day="{substring(date, 7, 2)}/{$sum div $count}"/>
    </xsl:template>
    <xsl:template match="distances|distance"/>
</xsl:stylesheet>

Explanation:

  • The Identity Transform outputs most of each car element as it appears in the source
  • Two separate keys are used: 1) to group by each car's ID and 2) to group by the combination of car ID and date
  • Only one additional template is needed to grab the first distance for each possible car ID and date pair, in which we output the average for that combination
查看更多
登录 后发表回答