Vijay
Vijay

Reputation: 911

Calculating the total of a calculated column using XSLT

I just learnt XSLT today when I wanted to pretty print the playlist export (xml) from itunes. I finally understood how XSLT pertains to XML and how useful it can be. I picked up the code from iTunes2Html and customized it for my own purposes. I have created a dynamic column which is the playtime/duration for a song (useful for people/djs who set start and end times!). What I wanted at the end of the display is a sumtotal of all the duration column. I can't figure out how to do that. I've researched on stack overflow and google with no luck so far. The results I have found have been confusing.

So can anybody can help me figure out how to calculate the total of a dynamic/calculated column? see similar question

Here is the relevant part of the XSLT

<td> <!-- calculating duration : formattime(end | total - start | 0), is there a simpler way to do it? -->
<xsl:variable name="totduration">
 <xsl:choose>
    <xsl:when test="string(number(following-sibling::Start_Time))='NaN'">
        <xsl:value-of select="following-sibling::Stop_Time"/>
    </xsl:when>
    <xsl:when test="string(number(following-sibling::Stop_Time))='NaN'">
        <xsl:value-of  select="number(following-sibling::Total_Time) - number(following-sibling::Start_Time)"/>
    </xsl:when>          
    <xsl:otherwise>
        <xsl:value-of  select="number(following-sibling::Stop_Time) - number(following-sibling::Start_Time)"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:variable>
<!-- for the javascript approach using jquery. didn't work -->
<span class="sumData" style="display:none"> <xsl:value-of select="$totduration"/></span> 
<xsl:call-template name="formatTime">
  <xsl:with-param name="t" select="$totduration"/>
</xsl:call-template>
</td>

Edit: Clarifying the logic of the duration calculation. Since start and stop are optional, the actual formula is (stop | total) - (start | 0). This means that if neither exists, then duration is identical to length i.e. it plays from start to end! Every song has that property. However if even one of the nodes (start or stop) is defined then the duration can be different from the total length of the song.

some sample XML

  <songlist>
<song>
  <Track_ID>169</Track_ID>
  <Name>AAAAA</Name>
  <Album>AAAAA</Album>
  <Genre>AAAAA</Genre>
  <Start_Time>78000</Start_Time>
  <Stop_Time>122000</Stop_Time>
  <Total_Time>357537</Total_Time>
</song>
<song>
  <Track_ID>174</Track_ID>
  <Name>BBBBBB</Name>
  <Artist>BBBBBB</Artist>
  <Album>BBBBBB</Album>
  <Genre>BBBBBB</Genre>
  <Stop_Time>120000</Stop_Time>
  <Total_Time>275043</Total_Time>
</song>
<song>
  <Track_ID>177</Track_ID>
  <Name>CCCCCC</Name>
  <Artist>CCCCCC</Artist>
  <Album>CCCCCC</Album>
  <Genre>CCCCCC</Genre>
  <Stop_Time>62000</Stop_Time>
  <Total_Time>287738</Total_Time>
</song>
<song>
  <Track_ID>180</Track_ID>
  <Name>DDDDDDD</Name>
  <Artist>DDDDDDD</Artist>
  <Album>DDDDDDD</Album>
  <Genre>DDDDDDD</Genre>
  <Start_Time>43000</Start_Time>
  <Total_Time>400274</Total_Time>
</song>

This is the output Screenshot

The Desired Output as it would appear at the bottom of the duration column (i.e. sum of all duration):

Total Playtime Duration - 9:43

Also is there a better way (that what is shown above) to do this formula in xslt? I am currently using xsl:choose to check for NaNs and use the alternative accordingly. I can't help but think that there has to be a better way.

formattime((stop | total) - (start | 0))

Upvotes: 0

Views: 6648

Answers (3)

Vijay
Vijay

Reputation: 911

<xsl:variable name="totalduration" select="
  sum($songs/song[Stop_Time > 0]/Stop_Time | $songs/song[not(Stop_Time > 0)]/Total_Time )
  -
  sum($songs/song/Start_Time)
" />
<p> Total Duration for playlist:   
  <xsl:call-template name="formatTime">
    <xsl:with-param name="t" select="$totalduration"/>
  </xsl:call-template>
</p>

This is the final code I ended up using thanks to @tomalak. I've put it here for future reference.

Upvotes: 0

Tomalak
Tomalak

Reputation: 338326

This should give you exactly what you are looking for:

<xsl:variable name="total" select="
  sum(song[Stop_Time &gt; 0]/Stop_Time | song[not(Stop_Time &gt; 0)]/Total_Time)
  -
  sum(song/Start_Time)
" />

For your XML sample this evaluates to 583274, i.e. 9m, 43s.

Upvotes: 1

dash1e
dash1e

Reputation: 7807

Use xpath function sum and select with the expression all the nodes to sum. For example

<xsl:value-of select="sum(/my/node)"/>

Upvotes: 0

Related Questions