如何按给定顺序对XML进行排序? (搞乱导出的iTunes播放列表)

时间:2015-09-07 06:46:22

标签: xml xslt itunes

在iTunes中,当您以XML格式导出播放列表时,它会自动按照“添加日期”而不是用户订购的顺序对其进行排序。接近XML文件的末尾,它列出了用户通过歌曲ID对其进行排序的播放列表的顺序,如下所示:

<key>Playlist Items</key>
            <array>
                <dict>
                    <key>Track ID</key><integer>5365</integer>
                </dict>
                <dict>
                    <key>Track ID</key><integer>5317</integer>
                </dict>
                <dict>
                    <key>Track ID</key><integer>5235</integer>
                </dict>
            <array>

我使用这个XSL转换了XML文档:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="/">
        <table>
            <tr>
                <th>Name</th>
                <th>Artist</th>
                <th>Year</th>

            </tr>
            <xsl:call-template name="records" />
        </table>
    </xsl:template>

    <xsl:template name="records">
        <xsl:for-each select="/*/*/dict[1]/dict">
            <xsl:element name="tr">
                <xsl:call-template name="songs" />
            </xsl:element>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="songs">

        <td>
            <xsl:value-of select="child::*[preceding-sibling::* = 'Track ID']" />
        </td>
        <td>
            <xsl:value-of select="child::*[preceding-sibling::* = 'Name']" />
        </td>
        <td>
            <xsl:value-of select="child::*[preceding-sibling::* = 'Artist']" />
        </td>

        </xsl:template>
</xsl:stylesheet>

我想知道如何根据原始XML文件末尾出现的用户指定顺序而不是“添加日期”来编辑我的XSL以转换我的播放列表以重新排序所有内容?

编辑 - 添加更多原始XML。以下是与我所做的XSL有关的片段:

<key>5189</key>
        <dict>
            <key>Track ID</key><integer>5189</integer>
            <key>Name</key><string>varsity jacket</string>
            <key>Artist</key><string>bayou</string>
            <key>Kind</key><string>MPEG audio file</string>
            <key>Size</key><integer>3532008</integer>
            <key>Total Time</key><integer>220107</integer>
            <key>Date Modified</key><date>2015-07-26T14:04:34Z</date>
            <key>Date Added</key><date>2015-07-26T14:04:17Z</date>
            <key>Bit Rate</key><integer>128</integer>
            <key>Sample Rate</key><integer>44100</integer>
            <key>Play Count</key><integer>1</integer>
            <key>Play Date</key><integer>3520959994</integer>
            <key>Play Date UTC</key><date>2015-07-29T00:26:34Z</date>
            <key>Skip Count</key><integer>2</integer>
            <key>Skip Date</key><date>2015-08-29T05:12:33Z</date>
            <key>Persistent ID</key><string>BE57D36AF01737E3</string>
            <key>Track Type</key><string>File</string>
            <key>Location</key><string>file:///Users/jason/Music/iTunes/iTunes%20Music/bayou/Unknown%20Album/varsity%20jacket.mp3</string>
            <key>File Folder Count</key><integer>4</integer>
            <key>Library Folder Count</key><integer>1</integer>
        </dict>

1 个答案:

答案 0 :(得分:0)

对您的代码提出必要但友好的建议:如果您对xsl:call-template满意,请不要将xsl:apply-templates与上下文一起使用,因为它会限制您的流量并使代码复杂化。

查看我的编辑。我采用了您的结构,但通过删除xsl:call-template进行了简化,但没有任何其他目的。

要排序,只需使用xsl:sort作为xsl:apply-templates的孩子。在这里,我按照艺术家的名字排序。如果需要,可以通过添加更多xsl:sort元素来添加更多排序键。

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

     <!-- from SO: http://stackoverflow.com/questions/32432619/how-to-sort-xml-in-given-order-messing-with-exported-itunes-playlists -->

    <xsl:output indent="yes" />

    <xsl:template match="/">
        <table>
            <tr>
                <th>Name</th>
                <th>Artist</th>
                <th>Year</th>

            </tr>
            <xsl:apply-templates select="*/*/dict[1]/dict" >
                <!-- sort by value of the name of the song -->
                <xsl:sort select="key[. = 'Name']/following-sibling::*[1]" />
            </xsl:apply-templates>
        </table>
    </xsl:template>

    <xsl:template match="dict">
        <tr>
            <xsl:apply-templates select="*" />
        </tr>
    </xsl:template>

    <xsl:template match="dict/key[. = 'Track ID' or . = 'Name' or . = 'Artist']">
        <td>
            <xsl:value-of select="following-sibling::*[1]" />
        </td>
    </xsl:template>

    <!-- ignore what we do not need -->
    <xsl:template match="dict/*" priority="-1" />
</xsl:stylesheet>

由于你没有提供有效的XML作为源文件(它有两个根元素),所以我发明了自己的符合原始代码的东西(即实际输出的东西),并添加了第二条记录以确保分类工作。一个友好的建议,如果您将来问XSLT问题,如果您包含一个(最小的)源文档,我们可以使用它来测试代码的修复,这将使我们更容易。

新的源文档:

<root>
    <record>
        <dict>
            <key>5189</key>
            <dict>
                <key>Track ID</key><integer>5189</integer>
                <key>Name</key><string>varsity jacket</string>
                <key>Artist</key><string>bayou</string>
                <key>Kind</key><string>MPEG audio file</string>
                <key>Size</key><integer>3532008</integer>
                <key>Total Time</key><integer>220107</integer>
                <key>Date Modified</key><date>2015-07-26T14:04:34Z</date>
                <key>Date Added</key><date>2015-07-26T14:04:17Z</date>
                <key>Bit Rate</key><integer>128</integer>
                <key>Sample Rate</key><integer>44100</integer>
                <key>Play Count</key><integer>1</integer>
                <key>Play Date</key><integer>3520959994</integer>
                <key>Play Date UTC</key><date>2015-07-29T00:26:34Z</date>
                <key>Skip Count</key><integer>2</integer>
                <key>Skip Date</key><date>2015-08-29T05:12:33Z</date>
                <key>Persistent ID</key><string>BE57D36AF01737E3</string>
                <key>Track Type</key><string>File</string>
                <key>Location</key><string>file:///Users/jason/Music/iTunes/iTunes%20Music/bayou/Unknown%20Album/varsity%20jacket.mp3</string>
                <key>File Folder Count</key><integer>4</integer>
                <key>Library Folder Count</key><integer>1</integer>
            </dict>
            <key>5190</key>
            <dict>
                <key>Track ID</key><integer>5190</integer>
                <key>Name</key><string>some song</string>
                <key>Artist</key><string>anton</string>
                <key>Kind</key><string>MPEG audio file</string>
                <key>Size</key><integer>3532008</integer>
                <key>Total Time</key><integer>220107</integer>
                <key>Date Modified</key><date>2015-07-26T14:04:34Z</date>
                <key>Date Added</key><date>2015-07-26T14:04:17Z</date>
                <key>Bit Rate</key><integer>128</integer>
                <key>Sample Rate</key><integer>44100</integer>
                <key>Play Count</key><integer>1</integer>
                <key>Play Date</key><integer>3520959994</integer>
                <key>Play Date UTC</key><date>2015-07-29T00:26:34Z</date>
                <key>Skip Count</key><integer>2</integer>
                <key>Skip Date</key><date>2015-08-29T05:12:33Z</date>
                <key>Persistent ID</key><string>BE57D36AF01737E3</string>
                <key>Track Type</key><string>File</string>
                <key>Location</key><string>file:///Users/jason/Music/iTunes/iTunes%20Music/bayou/Unknown%20Album/varsity%20jacket.mp3</string>
                <key>File Folder Count</key><integer>4</integer>
                <key>Library Folder Count</key><integer>1</integer>
            </dict>
        </dict>
    </record>
</root>

新的按名称排序输出:

<table>
   <tr>
      <th>Name</th>
      <th>Artist</th>
      <th>Year</th>
   </tr>
   <tr>
      <td>5190</td>
      <td>some song</td>
      <td>anton</td>
   </tr>
   <tr>
      <td>5189</td>
      <td>varsity jacket</td>
      <td>bayou</td>
   </tr>
</table>

另请注意:您的第一个代码段为array/dict,您的第二个代码段只有dict,但您的XSLT使用dict/dict,因此我更改了源代码结构以使其适合您的XSLT代码

你说:

  

按照原始XML文件末尾出现的用户指定顺序排序[...],而不是按照&#34;添加日期&#34;

您需要扩展我上面给出的示例。由于我不知道关于这部分的XML的结构,并且在问题中没有给出,我无法应用它。但是,我认为它将是底部的一个元素,所以应该很容易使用它。

例如,假设订单由/*/userorder/@by给出,@by包含与key元素匹配的值,您可以这样做:

<xsl:sort select="key[. = /*/userorder/@by]/following-sibling::*[1]" />