Reputation: 911
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
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
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
Reputation: 338326
This should give you exactly what you are looking for:
<xsl:variable name="total" select="
sum(song[Stop_Time > 0]/Stop_Time | song[not(Stop_Time > 0)]/Total_Time)
-
sum(song/Start_Time)
" />
For your XML sample this evaluates to 583274
, i.e. 9m, 43s
.
Upvotes: 1