Aug
14
I’m trying to learn how to abstract common elements of XSLT away. For example, the MusicDatabase’s shiny new XML output gives the run-length of a CD, or a track on it, in seconds. But, for output, we’d really like to show it as minutes and seconds (i.e. 308 would become 5:08).
This is fairly simple to do:
<xsl:value-of select="format-number(runlength div 60, '#')"/>: <xsl:value-of select="format-number(runlength mod 60, '00')"/>
However, I don’t want to have to repeat that everywhere, a) because I’m lazy and don’t want to have to go to the effort of finding the file it’s in every time I want it, and cutting and pasting from there, and b) because I worked that out myself on my second day of playing seriously with XSLT, and I’ll probably discover later that there’s a much better way, or that it doesn’t cope properly with some fringe case, and I won’t want to have to go through and change it everywhere it’s used (see Laziness above). Oh, and c) because it’s always good practice to do this sort of stuff, for lots of reasons that never seemed as convincing as laziness.
Initial research into this persuaded me that there were two main approaches: parameterisation (see Creating Generic XSLT Transforms), or named templates (see
The Tao of Recursion: Named Templates in XSLT, or Math and XSLT [with its 'Calculate pi using Leibnitz recursive named template']).
Named templates seemed the best way to go, so I added a secs_to_mins template:
<xsl:template name="secs_to_mins">
<xsl:param name="secs" />
<xsl:value-of select="format-number($secs div 60, '#')" />:
<xsl:value-of select="format-number($secs mod 60, '00')" />
</xsl:template>
And then called it:
<xsl:call-template name="secs_to_mins">
<xsl:with-param name="secs" select="runlength"/>
</xsl:call-template>
(It didn’t work at first, as I’d left the $ signs off, but it everything was fine once I realised that).
Then all I had to do was move it into its own file, and place at the top of any XSL file that wants it:
<xsl:import href="lib/secs_to_mins.xsl" />
Wahey! Now I can build lots of nice components to play with.
Now I just need to find a good way to play with XSLTunit or equivalent to build up a test suite for these…