Wednesday, July 7, 2010

XSLT and iTunes parsing into HTML table

I will now show some code that I have been tweaking from a site:

It wasn't working so I had to play with it some until I understood how it works. XSLT is powerful when it comes to converting xml to any format you want.
I will show the example xslt style document I changed from the site above to make really cool looking iTunes tables showing all your music sorted by genre and the times and sizes of each.

First download the Xalan

Find your itunes xml document in My Music folder in My Documents for your current user then open the iTunes folder and copy the iTunes Music Library.xml to your xalan folder and rename it to itunes.xml

Here is where mines was found:
C:\Documents and Settings\mike\My Documents\My Music\iTunes

Now make an itunes.xsl file and put this in it:


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:key name="songsByAlbum" match="dict"
use="string[preceding-sibling::key[1]='Album']"/>

<xsl:key name="songsByGenre" match="dict"
use="string[preceding-sibling::key[1]='Genre']"/>


<xsl:template match="/plist/dict/dict">
<html>
<style>
table,th,td{border:1px solid black;padding:3px;}
th{text-align:left;background-color:#3333CC;}
.indent{border:0px;width:10px;}
.genre{background-color:#7094FF;}
.album{background-color:#3366FF;color: #222}
</style>
<body>
<table>
<tr><th colspan="2">Genre / Album</th><th>Artist</th><th>Time</th><th>Size</th></tr>
<xsl:for-each select="dict[generate-id(.)=
generate-id(key('songsByGenre',string)[1])]">
<xsl:sort select="string[preceding-sibling::key[1]='Genre']"/>
<xsl:for-each select="key('songsByGenre',string)[1]">

<xsl:call-template name="albumsInGenre">
<xsl:with-param name="genre"
select="string[preceding-sibling::key[1]='Genre']"/>
</xsl:call-template>



</xsl:for-each>
</xsl:for-each>

</table>
</body>
</html>
</xsl:template>


<xsl:template name="albumsInGenre">
<xsl:param name="genre"/>

<tr><td class="genre" colspan='5'><b><xsl:value-of select="$genre"/></b></td></tr>

<xsl:variable name="song" select="/plist/dict/dict/dict"/>
<xsl:for-each select="$song[generate-id(.)=
generate-id(key('songsByAlbum',string[preceding-sibling::key[1]='Album'])[1])]">
<xsl:sort select="string[preceding-sibling::key[1]='Album']"/>
<xsl:for-each select="key('songsByAlbum',string[preceding-sibling::key[1]='Album'])
[string[preceding-sibling::key[1]='Genre']=$genre][1]">
<tr>
<td class="indent"> </td>
<td class="album" align='left'><xsl:call-template name="albumName"/></td>
<td class="album" align='left'><xsl:call-template name="artistName"/></td>
<td class="album" align='right'><xsl:call-template name="iTunesTimeAlbum"/></td>
<td class="album" align='right'><xsl:call-template name="iTunesSizeTotal"/></td>
</tr>
</xsl:for-each>
</xsl:for-each>
</xsl:template>

<xsl:template name="albumName">
<xsl:value-of select="string[preceding-sibling::key[1]='Album']"/>
</xsl:template>

<xsl:template name="artistName">
<xsl:choose>
<xsl:when test="true[preceding-sibling::key[1]='Compilation']">
<i>Compilation</i>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="string[preceding-sibling::key[1]='Artist']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template name="iTunesTimeAlbum">
<xsl:variable name="tracksInAlbum"
select="key('songsByAlbum',string[preceding-sibling::key[1]='Album'])"/>
<xsl:variable name="t"
select="sum($tracksInAlbum/integer[preceding-sibling::key[1]='Total Time'])"/>
<xsl:call-template name="formatTime">
<xsl:with-param name="t" select="$t"/>
</xsl:call-template>
</xsl:template>

<xsl:template name="formatTime">
<xsl:param name="t"/>
<xsl:if test="$t != 0">
<xsl:variable name="h" select="floor(($t div (1000*60*60)))"/>
<xsl:variable name="m" select="floor(($t div (1000*60)) mod 60)"/>
<xsl:variable name="s" select="floor(($t div 1000) mod 60)"/>
<xsl:if test="$h != 0"><xsl:value-of select="$h"/>:</xsl:if>
<xsl:value-of select="format-number($m,'00')"/>:<xsl:value-of select="format-number($s,'00')"/>
</xsl:if>
</xsl:template>

<xsl:template name="iTunesSizeTotal">
<xsl:variable name="tracksInAlbum"
select="key('songsByAlbum',string[preceding-sibling::key[1]='Album'])"/>
<xsl:variable name="s"
select="sum($tracksInAlbum/integer[preceding-sibling::key[1]='Size'])"/>
<xsl:value-of select="format-number($s div (1000*1000),'00.00')"/>MB
</xsl:template>

<xsl:template name="formatSize">
<xsl:param name="s"/>
<xsl:if test="$s != 0">
<xsl:value-of select="floor($s)"/>GB
</xsl:if>
</xsl:template>

<xsl:template name="iTunesSizeTotalorig">
<xsl:variable name="s" select="sum(dict/integer[preceding-sibling::key[1]='Size'])"/>
<xsl:value-of select="floor($s div (1000*1000))"/>MB
</xsl:template>

</xsl:stylesheet>



Now you just open command prompt and paste this into it:
set CLASSPATH=C:\JavaDev\Java5\ojdbc5.jar;.
set CLASSPATH=%CLASSPATH%;C:\xalan-j_2_7_1\xalan.jar;.
set CLASSPATH=%CLASSPATH%;C:\xalan-j_2_7_1\serializer.jar
set CLASSPATH=%CLASSPATH%;C:\xalan-j_2_7_1\xercesImpl.jar
set CLASSPATH=%CLASSPATH%;C:\xalan-j_2_7_1\xml-apis.jar
set CLASSPATH=%CLASSPATH%;C:\xalan-j_2_7_1\xsltc.jar

Next paste this line:
java org.apache.xalan.xslt.Process -IN itunes.xml -XSL itunes.xsl -HTML > itunes.html

Now after pressing enter you should have an html file in the xalan folder and it will be formated like this:

Genre / AlbumArtistTimeSize
General Classical
Bibbidi Bobbidi BachScott Tennant07:3107.22MB
Soundtrack
Les Miserables 10th Anniversary Concert Disc 11995 Royal Albert Hall Concert Cast03:1503.12MB
Les Miserables 10th Anniversary Concert Disc 21995 Royal Albert Hall Concert Cast03:0903.02MB

Isn't that cool? You could also use the path to the itunes xml file in the xalan if you like what you see and then it will just convert to html what ever you have now.
This works for me too if you are in the xalan folder or where ever you have your itunes.xsl file and where you want your itenues.html to be written or you may change those as well:
java org.apache.xalan.xslt.Process -IN "C:\Documents and Settings\mike\My Documents\My Music\iTunes\iTunes Music Library.xml" -XSL itunes.xsl -HTML > itunes.html

6 comments:

Anonymous said...

What is the reason; you have to face matt cutts as it makes relevant text to visible with
the mouse click. Research will show you if your rank is correct.


Visit my blog post :: Marketing Seo

Anonymous said...

get back your ex boyfriend Program with Cranberry
JuiceStep 1: You need to get THC out of your system in
order to cook and eat wonderful meals.

Here is my blog post ... web page

Anonymous said...

Excellent blog you have got here.. It's hard to find excellent writing like yours nowadays. I honestly appreciate people like you! Take care!!

Here is my site Michael Kors (http://overuc.com/michaelkors.html)

Anonymous said...

Hi there! This is kind of off topic but I need some advice from an established blog.

Is it tough to set up your own blog? I'm not very techincal but I can figure things out pretty fast. I'm thinking about creating
my own but I'm not sure where to begin. Do you have any tips or suggestions? Cheers

Here is my webpage Boutique Air Jordan

Anonymous said...

Spot on with this write-up, I absolutely think this amazing site
needs a lot more attention. I'll probably be returning to see more, thanks for the information!

Also visit my page - Nike Air Max

Anonymous said...

I am really impressed with your writing skills as well as with the
layout on your weblog. Is this a paid theme or did you modify it
yourself? Anyway keep up the nice quality writing, it is
rare to see a nice blog like this one these days.


Feel free to surf to my web blog Air Max