How do I use SUM and AVERAGE in XSL?

一曲冷凌霜 提交于 2019-12-11 02:47:24

问题


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


回答1:


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


来源:https://stackoverflow.com/questions/8934166/how-do-i-use-sum-and-average-in-xsl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!