XSLT script létrehoz album lista az iTunes XML

Posted on

Amikor kaptam magam, iPod, megtaláltam a nyomtatott listák elérhető az iTunes programot, nem voltak különösen nagy (annak ellenére, hogy az interaktív felület, hogy kiváló), nem egy tömör összefoglaló listája albumok. Mivel az iTunes tárolja a könyvtár, mint az XML, régen XSLT, hogy hozzon létre egy lista jobban tetszik. Mivel én inkább hallgatni albumok inkább, mint a szinglik, azt akartam, albumok listája szerint csoportosítva műfaj.

Használja ezt a forgatókönyvet, mentsd meg a albumList.xml pedig albumList.xsl alábbi ábrán látható, hogy a My Music/iTunes mappát, majd nyissa meg albumList.xml az Internet Explorer 6+ vagy Mozilla Firefox (IE5 nem működik; még nem tesztelt más böngészők).

Az iTunes XML ‘tulajdon lista’

Az iTunes könyvtárában tárolt, mint az XML fájl neve iTunes Music Library.xml. Ez használ egy általános XML nyelv néven ismert ingatlan lista, vagy plist, amely tartalmazza az információkat, kulcs/érték párok. Ahelyett, hogy személyre szabott leírja a dalok, lehet leírására tulajdonságait több vagy kevesebb semmit. Így az XML néz ki:

<plist version="1.0">
  <dict>
    <key>Tracks</key>
    <dict>
      <key>638</key>
      <dict>
        <key>Track ID</key><integer>638</integer>
        <key>Name</key><string>Take Me To The River</string>
        <key>Artist</key><string>Talking Heads</string>
        <key>Composer</key><string>Al Green &#38; M. Hodges</string>
        <key>Album</key><string>Stop Making Sense</string>
        <key>Genre</key><string>Alternative &#38; Punk</string>
        ... etc ...
      </dict>
    </dict>
  </dict>
</plist>

Ez azt jelenti, hogy találni, mondjuk, az album neve, azt kell, hogy megfeleljen egy <string> egy közvetlenül megelőző testvér <key> az ‘Album’:

string[preceding-sibling::key[1]='Album']

A <string> elemet, ahol az 1 <key> elem az előző-testvér tengely az a értéke ‘Album’.

Bár ez egy kényelmes általános rendeltetésű XML nyelv, biztos, hogy sokkal összetettebb manipulálni, mint egy XML nyelv szabott képviselik az egyes zeneszámok, akkor vegyél egy mély lélegzetet, hogy mi következik!

Egyre albumok listája

Az iTunes az XML dalokat. Az album a dal jelenik meg semmi, tényleg, mint egy attribútum a dalt, szóval egy egyszerű megközelítést ad az album neve egyszer minden dal, ami megjelenik. Ezért, hogy megfelelő listát, albumok, használja inkább okos trükk áll rendelkezésre az <xsl:key> elemet, majd az key(), majd generál-id() függvények.

Mások kifejtették, a használata <xsl:key> jobb, akkor én is, de röviden itt, az <xsl:key> elemet épít egy listát a <dict> csomópontok képviselő dalokat. Az <xsl:for-each> elemet, majd kiválasztja <dict> (azaz dal) elemek, amelyek az automatikusan generált azonosító megegyezik az automatikusan generált azonosítója az első csomópont által visszaadott a key() függvény. Nem, forog velem a világ is. A kapott stíluslap, hogy albumok listája (a kapcsolódó művészek):

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

<xsl:template match="/plist/dict/dict">
  <html>
    <body>
      <table>

        <xsl:for-each select="dict[generate-id(.)=
            generate-id(key('songsByAlbum',string)[1])]">
          <xsl:sort select="string[preceding-sibling::key[1]='Album']"/>
          <tr>
            <td><xsl:value-of select="string[preceding-sibling::key[1]='Album']"/></td>
            <td><xsl:value-of select="string[preceding-sibling::key[1]='Artist']"/></td>
          </tr>
        </xsl:for-each>

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

Ez a probléma a válogatás. Akkor vedd fel bárki is az, hogy a művész az első dal egy összeállítás, amely úgy néz ki, kissé furcsa. A javításhoz használni a ‘Része egy Összeállítás’ zászló, a következőképpen:

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

<xsl:template match="/plist/dict/dict">
  <html>
    <body>
      <table>

        <xsl:for-each select="dict[generate-id(.)=generate-id(key('albums',string)[1])]">
          <xsl:sort select="string[preceding-sibling::key[1]='Album']"/>
          <tr>
            <td><xsl:call-template name="albumName"/></td>
            <td><xsl:call-template name="artistName"/></td>
          </tr>
        </xsl:for-each>

      </table>
    </body>
  </html>
</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>

Törtem le a fő sablon különálló sablonok album, előadó – XSLT nehéz lehet követni a legjobb időt, én modularise a sablonok, amennyit csak lehet.

Albumok listája szerint csoportosítva műfaj

Az a baj ezzel a listával, ahogy a zene minden tört össze. Nem igazán tetszett, hogy a Abba Máté Passió dörzsölés vállát, Hogy Van Értelme.

A csoport az albumok műfaj, nem egy technika által kidolgozott Steve Muench, Oracle ‘XML Műszaki Evangélista’, szinkronizált ‘Muenchian egyesülés’.

Megint mások kifejtették, hogy ez jobb, mint én, szóval elég annyit mondani (ha szeretnéd kipróbálni, hogy kövesse a művelet az XSL), hogy használja a generál-id() függvény az XSL kulcsok meghatározása a dalokat a Műfaj, az Album, illetve a pont, ahol a sablon albumsInGenre hívják, a jelenlegi helyzetben az első <dict> a dal belül minden műfaj.

Belül a albumsInGenre sablon, ugyanazt a technikát használni ahhoz, hogy az első dal belül minden Album, annak érdekében, hogy az album nevét, majd művész. Én is használni egy további állítmány, hogy további szűrő ez a csomópont-annak beállítása, hogy a műfaj telt el, mint egy paraméter, hogy a sablon.

(Könnyebb lesz az életünk, a XSLT 2.0, amely-minden-csoport elem).

A stíluslap néz ki:

<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>
    <body>
      <table>

        <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 colspan='3'><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> </td>
        <td><xsl:call-template name="albumName"/></td>
        <td><xsl:call-template name="artistName"/></td>
      </tr>
    </xsl:for-each>
  </xsl:for-each>
</xsl:template>

A keletkező album lista így néz ki:

Electronicán/Tánc
Boulevard St. Germain
Dehli9 Tosca
On Land Brian Eno
Jazz
Madar Jan Garbarek
The Hot Fives & Sevens Louis Armstrong & The Hot Five

Ha csak az albumok az iPod, sokkal inkább, mint az összes albumot iTunes library-ban, akkor egy plusz feltétel, hogy egészül ki, hogy a belső-leginkább-minden, szóval hogy ez lesz:

<xsl:for-each select="key('songsByAlbum',string[preceding-sibling::key[1]='Album'])
        [string[preceding-sibling::key[1]='Genre']=$genre]
        [not(true[preceding-sibling::key[1]='Disabled'])][1]">

Hozzátéve, nyomon alkalommal

Hogy idáig eljutott, látni akartam az időtartam minden album. Az időtartam minden dal tárolása (ezredmásodpercben) ellen egy Teljes Idő kulcs, szóval a sablon, hogy ez:

<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"/>h</xsl:if>
    <xsl:value-of select="format-number($m,'00')"/>m
    <xsl:value-of select="format-number($s,'00')"/>s
  </xsl:if>
</xsl:template>

Újra, ha szeretnéd látni az időtartam az iPod helyett iTunes library-ban (ha csak a számokat egy albumot már kiválasztott át az iPod), extra állapotban van, hogy ki a válasszuk a változó:

<xsl:variable name="t"
      select="sum($tracksInAlbum/integer[preceding-sibling::key[1]='Total Time']
      [not(../true[preceding-sibling::key[1]='Disabled'])])"/>

Hasonló sablont ad a teljes idő zenét az iTunes könyvtár (vagy az iPod):

<xsl:template name="iTunesTimeTotal">
  <xsl:variable name="t"
      select="sum(dict/integer[preceding-sibling::key[1]='Total Time'])"/>
  <xsl:call-template name="formatTime">
    <xsl:with-param name="t" select="$t"/>
  </xsl:call-template>
</xsl:template>

Ha azt akarta, hogy a teljes merevlemez méret a dalokat, rendelkezésre áll ellen a Méret gomb:

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

Nyitás a lista közvetlenül a böngészőben

Ahelyett, hogy speciális XML/XSLT eszközök, én nyitott a lista közvetlenül a böngészőben. Ehhez létre egy ‘papír’ XML-fájl, amely meghatározza, melyik stíluslapot kell alkalmazni, hogy mi XML-fájl segítségével a <?xml-stylesheet> feldolgozási utasítás, valamint a <incl> elem:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="albumList.xsl" type="text/xsl"?>
<wrapper>
  <incl file="iTunes Music Library.xml"/>
</wrapper>

Én akkor egy sablon tetején az XSL stíluslapra, mely megegyezik a <wrapper> elem tettem körül a mellékelt XML fájlt, majd alkalmazza a stíluslap sablonok, hogy a mellékelt XML fájlt.

<xsl:template match="/wrapper">
    <xsl:apply-templates select="document(incl/@file)"/>
  </xsl:template>

Ez kellene, hogy a jelenlegi böngésző; ellenőriztem az Internet Explorer (6.0+) vagy a Firefox.

Megjegyzés: egy alternatív megközelítés lenne, ha előre folyamat a p-lista XML egy hagyományos szerkezetű, amint azt a www.xmldatabases.org/WK/blog/1086?t=item van, ami akkor lenne egyszerűbb manipulálni a XSLT. Kész vagyok együtt élni a megelőző-testvér építeni annak érdekében, hogy képes generálni a lista egyetlen lépés.


Mindez együttvéve a stíluslap alatt. Ez inkább egy nagy stíluslap, de a fenti információkat, akkor képesnek kell lennie arra, hogy szedje szét, majd a részeket, amiket szeretnél.

… szóval most van egy gyors referencia listája, az albumok, az iPod.


Használja ezt a forgatókönyvet, annak alap-vagy a teljes formát, mentsd meg a albumList.xml pedig albumList.xsl alábbi ábrán látható, hogy a My Music/iTunes mappát, majd nyissa meg albumList.xml a böngészők (IE6 vagy Firefox). Ha azt szeretné, hogy személyre szabott, az elrendezés, a fenti irányelveknek meg kell tenni, hogy keverheted az alkatrészeket, szükség szerint.


Fájl albumList.xml (meghatározza, hogy alkalmazni albumList.xsl, hogy az iTunes Music Library.xml):

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="albumList.xsl" type="text/xsl"?>
<wrapper>
  <incl file="iTunes Music Library.xml"/>
</wrapper>

Fájl albumList.xsl alap verzió (listák neve & előadó albumot, az iPod):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <!-- (c) Chris Veness 2005 -->
  <xsl:output method="html" encoding="UTF-8" indent="yes"/>

  <!-- match the wrapper and apply templates to the <incl> xml file -->
  <xsl:template match="/wrapper">
    <xsl:apply-templates select="document(incl/@file)/plist/dict/dict"/>
  </xsl:template>


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


  <xsl:template match="dict">
    <html>
      <head>
        <title>iPod Album Listing</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
      </head>
      <body>
        <table>

          <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"/>

    <!-- genre header -->
    <tr><td colspan='3'><b><xsl:value-of select="$genre"/></b></td></tr>

    <!-- output each album in genre -->
    <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]
          [not(true[preceding-sibling::key[1]='Disabled'])][1]">
        <tr valign='top'>
          <td width='20'> </td>
          <!-- the album name: -->
          <td><xsl:value-of select="string[preceding-sibling::key[1]='Album']"/></td>
          <!-- the artist: -->
          <td>
            <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>
          </td>
        </tr>
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Fájl albumList.xsl teljes verzió (magában foglalja a teljes iTunes könyvtár szer & összesen):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <!-- (c) Chris Veness 2005-2006 -->
  <xsl:output method="html" encoding="UTF-8" indent="yes"/>


  <!-- match the wrapper and apply templates to the <incl> xml file -->
  <xsl:template match="/wrapper">
    <xsl:apply-templates select="document(incl/@file)/plist/dict/dict"/>
  </xsl:template>


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


  <xsl:template match="dict">
    <html>
      <head>
        <title>iTunes Album Listing</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <style type='text/css'> td { vertical-align: top; padding-right: 1em; } </style>
      </head>
      <body>
        <table>

          <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>

          <!-- totals -->
          <tr>
            <td colspan='4' style='color: gray'><b>Total</b></td>
            <td style='color: gray' align='right'><xsl:call-template name="iPodTimeTotal"/></td>
            <td style='color: gray' align='right'><xsl:call-template name="iTunesTimeTotal"/></td>
          </tr>
          <tr>
            <td colspan='4'> </td>
            <td style='color: gray' align='right'><xsl:call-template name="iPodSizeTotal"/></td>
            <td style='color: gray' align='right'><xsl:call-template name="iTunesSizeTotal"/></td>
          </tr>

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


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

    <tr>  <!-- genre header -->
      <td colspan='4'><b><xsl:value-of select="$genre"/></b></td>
      <td align='right' style='color: gray'><i>iPod</i></td>
      <td align='right' style='color: gray'><i>iTunes</i></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]">
          <!--  for albums on iPod only, add
                [not(true[preceding-sibling::key[1]='Disabled'])] -->
        <tr>
          <td> </td>
          <td><xsl:call-template name="album"/></td>
          <td><xsl:call-template name="artist"/></td>
          <td align='right'><xsl:call-template name="iPodTimeAlbum"/></td>
          <td align='right'><xsl:call-template name="iTunesTimeAlbum"/></td>
        </tr>
      </xsl:for-each>
    </xsl:for-each>
    <tr><td colspan='6'>&#160;</td></tr>  <!-- space between genres -->
  </xsl:template>


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


  <xsl:template name="artist">
    <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="iPodTimeAlbum">
    <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']
            [not(../true[preceding-sibling::key[1]='Disabled'])])"/>
    <xsl:call-template name="formatTime">
      <xsl:with-param name="t" select="$t"/>
    </xsl:call-template>
  </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="iPodTimeTotal">
    <xsl:variable name="t" select="sum(dict/integer[preceding-sibling::key[1]='Total Time']
        [not(../true[preceding-sibling::key[1]='Disabled'])])"/>
    <xsl:call-template name="formatTime">
      <xsl:with-param name="t" select="$t"/>
    </xsl:call-template>
  </xsl:template>


  <xsl:template name="iTunesTimeTotal">
    <xsl:variable name="t" select="sum(dict/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="iPodSizeTotal">
    <xsl:variable name="s" select="sum(dict/integer[preceding-sibling::key[1]='Size']
        [not(../true[preceding-sibling::key[1]='Disabled'])])"/>
    <xsl:value-of select="floor($s div (1000000)) div 1000"/>GB
  </xsl:template>


  <xsl:template name="iTunesSizeTotal">
    <xsl:variable name="s" select="sum(dict/integer[preceding-sibling::key[1]='Size'])"/>
    <xsl:value-of select="floor($s div (1000000)) div 1000"/>GB
  </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:stylesheet>

Eredetileg egy http://www.movable-type.co.uk/scripts/itunes-albumlist.html. Készítette http://hunsci.com