使用单个XSLT转换源文件并基于类对元素进行排序

时间:2013-07-19 19:47:52

标签: html xml xslt

我必须将以下源文件转换为XML并根据class属性对元素进行排序。转换工作正常,但我无法应用基于class属性的排序,因此所有HD歌曲和SD歌曲都被分组。我尝试过xsl:perform-sort,但我不确定在XSLT中应用它的位置和方法。

这是我的源文件:

<html>
<head>
  <title></title>
</head>
<body>

  <!-- This is my first comment -->
 <ol>
   <li>3 Song 1</li>
   <li>4 Song 2</li>
   <li>5 Song 3</li>
   <li>7 Song 4</li>
   <li>8 Song 5</li>
   <li>10 Song 6</li>
   <li>14 Song 7</li>
   <li>16 Song 8</li>
   <li>18 Song 9</li>
   <li>19 Song 10</li>
   <li>26 Song 11</li>
   <li>29 Song 12</li>
   <li>31 Song 13</li>
   <li>34 Song 14</li>
   <li>37 Song 15</li>
   <li>39 Song 16</li>
   <li>41 Song 17</li>
   <li>44 Song 18</li>
  </ol>

</body>
</html>

这是我的XSLT 2.0:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xspf="http://xspf.org/ns/0/"
    xmlns:vlc="http://www.videolan.org/vlc/playlist/ns/0/" version="2">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
    <!--    It is very important to add the prefix xspf to the xmlns for xspf otherwise the sorting does not work-->
    <!--This identity transform template allows to copy the whole document and then drop all the parts that we don't want to keep-->

    <xsl:template match="/">

        <xsl:copy>

            <xsl:apply-templates/>


                <xsl:variable name="tracks">
                    <xsl:perform-sort select="trackList/track">
                        <xsl:sort select="title/@class" data-type="text" />

                    </xsl:perform-sort>
                </xsl:variable>
               <trackList>
                    <xsl:copy-of select="$tracks"/>
               </trackList>

        </xsl:copy>

    </xsl:template>

    <!-- Drop the content of the head, hr, and h1 elements -->
    <xsl:template match="head|hr|h1"/>

    <!--Copy the content of <ol> and its children-->
    <xsl:template match="ol">
        <!-- TrackList is case sensitive and it was not working without the proper-->
        <trackList>
            <xsl:apply-templates/>
        </trackList>
    </xsl:template>


    <!--Copy the content of <li> and its content-->

    <xsl:template name="mylist" match="li">

        <!-- Create new elements track and title as its child and grab the current content of li text, then use the second group of string using tokenize() -->
        <track>

            <location>
                <!-- The substring-before functionality allows to grab the first set of characters/word/number before the provided arg$, in this case space ' '-->
                <xsl:value-of select="concat('http://localhost/auto/v',substring-before(., ' '),'?dlna')"
                />
            </location>

            <title>
                <xsl:variable name="cleaned" select="replace(.,'\(HD\)|-DTV',' HD')"/>
                <!--              Check if track title contains HD create a class for SD or HD for it -->
                <xsl:choose>
                    <xsl:when test="contains($cleaned, 'HD')">
                        <xsl:attribute name="class">
                            <xsl:text>HD</xsl:text>
                        </xsl:attribute>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:attribute name="class">
                            <xsl:text>SD</xsl:text>
                        </xsl:attribute>
                    </xsl:otherwise>
                </xsl:choose>

                <!-- Create a variable to hold the cleaned title for every track -->

                <!--<xsl:value-of select="replace(.,'(HD)','HD',substring-after(., ' '))" />-->
                <xsl:value-of select="substring-after($cleaned, ' ')"/>


            </title>
            <extension application="http://www.videolan.org/vlc/playlist/0">
                <vlc:id>
                    <!-- Count the number of <li> as they represent a single track -->
                    <xsl:number count="li"/>
                    <!--<xsl:value-of select="substring-before(., ' ')"/>-->
                </vlc:id>
            </extension>
        </track>
    </xsl:template>

    <!--Copy the content of <body> and its children. This snippet was at the beginning of the document, but then I moved it to the end of the XSLT-->

    <xsl:template match="body">
        <playlist>
            <title>Playlist</title>

            <xsl:apply-templates/>

            <!-- By putting the apply-templates above this snippet it makes it generate after the whole document, which is what I wanted to achieve. -->
            <!-- For every substring-before create a list of vlc:item as found in the automatically created VLC playlist-->
            <extension application="http://www.videolan.org/vlc/playlist/0">
                <xsl:for-each select="(ol/li/text())">
                    <!-- This allows to create self-closing attribute tag for vlc:id tid-->
                    <xsl:variable name="vlcname">
                        <xsl:value-of select="substring-before(., ' ')"/>
                    </xsl:variable>
                    <xsl:element name="vlc:item">
                        <xsl:attribute name="tid">
                            <!-- Count the number of <li> as they represent a single track -->
                            <xsl:number count="li" format="0"/>
                        </xsl:attribute>
                    </xsl:element>
                </xsl:for-each>
            </extension>
        </playlist>
    </xsl:template>
</xsl:stylesheet>

生成的XML应如下所示:

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

<playlist xmlns:xspf="http://xspf.org/ns/0/"
          xmlns:vlc="http://www.videolan.org/vlc/playlist/ns/0/">
   <title>Playlist</title>


   <trackList>
      <track>
         <location>http://localhost/auto/v34?dlna</location>
         <title class="HD">Song 14 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>14</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v44?dlna</location>
         <title class="HD">Song 18 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>18</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v7?dlna</location>
         <title class="HD">Song 4 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>4</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v19?dlna</location>
         <title class="HD">Song 10 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>10</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v3?dlna</location>
         <title class="SD">Song 1</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>1</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v4?dlna</location>
         <title class="SD">Song 2</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>2</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v5?dlna</location>
         <title class="SD">Song 3</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>3</vlc:id>
         </extension>
      </track>     
      <track>
         <location>http://localhost/auto/v8?dlna</location>
         <title class="SD">Song 5</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>5</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v10?dlna</location>
         <title class="SD">Song 6</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>6</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v14?dlna</location>
         <title class="SD">Song 7</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>7</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v16?dlna</location>
         <title class="SD">Song 8</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>8</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v18?dlna</location>
         <title class="SD">Song 9</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>9</vlc:id>
         </extension>
      </track>

      <track>
         <location>http://localhost/auto/v26?dlna</location>
         <title class="SD">Song 11</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>11</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v29?dlna</location>
         <title class="SD">Song 12</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>12</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v31?dlna</location>
         <title class="SD">Song 13</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>13</vlc:id>
         </extension>
      </track>

      <track>
         <location>http://localhost/auto/v37?dlna</location>
         <title class="SD">Song 15</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>15</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v39?dlna</location>
         <title class="SD">Song 16</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>16</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v41?dlna</location>
         <title class="SD">Song 17</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>17</vlc:id>
         </extension>
      </track>

  </trackList>

   <extension application="http://www.videolan.org/vlc/playlist/0">
      <vlc:item tid="1"/>
      <vlc:item tid="2"/>
      <vlc:item tid="3"/>
      <vlc:item tid="4"/>
      <vlc:item tid="5"/>
      <vlc:item tid="6"/>
      <vlc:item tid="7"/>
      <vlc:item tid="8"/>
      <vlc:item tid="9"/>
      <vlc:item tid="10"/>
      <vlc:item tid="11"/>
      <vlc:item tid="12"/>
      <vlc:item tid="13"/>
      <vlc:item tid="14"/>
      <vlc:item tid="15"/>
      <vlc:item tid="16"/>
      <vlc:item tid="17"/>
      <vlc:item tid="18"/>
   </extension>
</playlist>

1 个答案:

答案 0 :(得分:1)

您需要对序列执行xsl:perform-sort。我通过删除与/匹配的模板并修改与ol匹配的模板来略微修改了您的XSLT。 (并添加了xsl:strip-space以获得更好看的输出。如果您的输入有重要的空格,可能需要删除它。)

XML输入(向HD添加了一些li

<html>
    <head>
        <title></title>
    </head>
    <body>

        <!-- This is my first comment -->
        <ol>
            <li>3 Song 1</li>
            <li>4 Song 2</li>
            <li>5 Song 3 HD</li>
            <li>7 Song 4</li>
            <li>8 Song 5</li>
            <li>10 Song 6 HD</li>
            <li>14 Song 7</li>
            <li>16 Song 8</li>
            <li>18 Song 9</li>
            <li>19 Song 10 HD</li>
            <li>26 Song 11</li>
            <li>29 Song 12</li>
            <li>31 Song 13 HD</li>
            <li>34 Song 14</li>
            <li>37 Song 15</li>
            <li>39 Song 16</li>
            <li>41 Song 17 HD</li>
            <li>44 Song 18</li>
        </ol>

    </body>
</html>

更新了XSLT 2.0

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xspf="http://xspf.org/ns/0/"
    xmlns:vlc="http://www.videolan.org/vlc/playlist/ns/0/" version="2">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <!--    It is very important to add the prefix xspf to the xmlns for xspf otherwise the sorting does not work-->
    <!--This identity transform template allows to copy the whole document and then drop all the parts that we don't want to keep-->

    <!-- Drop the content of the head, hr, and h1 elements -->
    <xsl:template match="head|hr|h1"/>

    <!--Copy the content of <ol> and its children-->
    <xsl:template match="ol">
        <!-- TrackList is case sensitive and it was not working without the proper-->
        <trackList>         
            <xsl:variable name="tracks">
                <xsl:apply-templates/>
            </xsl:variable>

            <xsl:perform-sort select="$tracks/*">
                <xsl:sort select="title/@class"/>
            </xsl:perform-sort>         
        </trackList>
    </xsl:template>


    <!--Copy the content of <li> and its content-->

    <xsl:template name="mylist" match="li">

        <!-- Create new elements track and title as its child and grab the current content of li text, then use the second group of string using tokenize() -->
        <track>

            <location>
                <!-- The substring-before functionality allows to grab the first set of characters/word/number before the provided arg$, in this case space ' '-->
                <xsl:value-of select="concat('http://localhost/auto/v',substring-before(., ' '),'?dlna')"
                />
            </location>

            <title>
                <xsl:variable name="cleaned" select="replace(.,'\(HD\)|-DTV',' HD')"/>
                <!--              Check if track title contains HD create a class for SD or HD for it -->
                <xsl:choose>
                    <xsl:when test="contains($cleaned, 'HD')">
                        <xsl:attribute name="class">
                            <xsl:text>HD</xsl:text>
                        </xsl:attribute>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:attribute name="class">
                            <xsl:text>SD</xsl:text>
                        </xsl:attribute>
                    </xsl:otherwise>
                </xsl:choose>

                <!-- Create a variable to hold the cleaned title for every track -->

                <!--<xsl:value-of select="replace(.,'(HD)','HD',substring-after(., ' '))" />-->
                <xsl:value-of select="substring-after($cleaned, ' ')"/>


            </title>
            <extension application="http://www.videolan.org/vlc/playlist/0">
                <vlc:id>
                    <!-- Count the number of <li> as they represent a single track -->
                    <xsl:number count="li"/>
                    <!--<xsl:value-of select="substring-before(., ' ')"/>-->
                </vlc:id>
            </extension>
        </track>
    </xsl:template>

    <!--Copy the content of <body> and its children. This snippet was at the beginning of the document, but then I moved it to the end of the XSLT-->

    <xsl:template match="body">
        <playlist>
            <title>Playlist</title>

            <xsl:apply-templates/>

            <!-- By putting the apply-templates above this snippet it makes it generate after the whole document, which is what I wanted to achieve. -->
            <!-- For every substring-before create a list of vlc:item as found in the automatically created VLC playlist-->
            <extension application="http://www.videolan.org/vlc/playlist/0">
                <xsl:for-each select="(ol/li/text())">
                    <!-- This allows to create self-closing attribute tag for vlc:id tid-->
                    <xsl:variable name="vlcname">
                        <xsl:value-of select="substring-before(., ' ')"/>
                    </xsl:variable>
                    <xsl:element name="vlc:item">
                        <xsl:attribute name="tid">
                            <!-- Count the number of <li> as they represent a single track -->
                            <xsl:number count="li" format="0"/>
                        </xsl:attribute>
                    </xsl:element>
                </xsl:for-each>
            </extension>
        </playlist>
    </xsl:template>
</xsl:stylesheet>

<强>输出

<playlist xmlns:xspf="http://xspf.org/ns/0/"
          xmlns:vlc="http://www.videolan.org/vlc/playlist/ns/0/">
   <title>Playlist</title>
   <trackList>
      <track>
         <location>http://localhost/auto/v5?dlna</location>
         <title class="HD">Song 3 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>3</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v10?dlna</location>
         <title class="HD">Song 6 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>6</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v19?dlna</location>
         <title class="HD">Song 10 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>10</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v31?dlna</location>
         <title class="HD">Song 13 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>13</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v41?dlna</location>
         <title class="HD">Song 17 HD</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>17</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v3?dlna</location>
         <title class="SD">Song 1</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>1</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v4?dlna</location>
         <title class="SD">Song 2</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>2</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v7?dlna</location>
         <title class="SD">Song 4</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>4</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v8?dlna</location>
         <title class="SD">Song 5</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>5</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v14?dlna</location>
         <title class="SD">Song 7</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>7</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v16?dlna</location>
         <title class="SD">Song 8</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>8</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v18?dlna</location>
         <title class="SD">Song 9</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>9</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v26?dlna</location>
         <title class="SD">Song 11</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>11</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v29?dlna</location>
         <title class="SD">Song 12</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>12</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v34?dlna</location>
         <title class="SD">Song 14</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>14</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v37?dlna</location>
         <title class="SD">Song 15</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>15</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v39?dlna</location>
         <title class="SD">Song 16</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>16</vlc:id>
         </extension>
      </track>
      <track>
         <location>http://localhost/auto/v44?dlna</location>
         <title class="SD">Song 18</title>
         <extension application="http://www.videolan.org/vlc/playlist/0">
            <vlc:id>18</vlc:id>
         </extension>
      </track>
   </trackList>
   <extension application="http://www.videolan.org/vlc/playlist/0">
      <vlc:item tid="1"/>
      <vlc:item tid="2"/>
      <vlc:item tid="3"/>
      <vlc:item tid="4"/>
      <vlc:item tid="5"/>
      <vlc:item tid="6"/>
      <vlc:item tid="7"/>
      <vlc:item tid="8"/>
      <vlc:item tid="9"/>
      <vlc:item tid="10"/>
      <vlc:item tid="11"/>
      <vlc:item tid="12"/>
      <vlc:item tid="13"/>
      <vlc:item tid="14"/>
      <vlc:item tid="15"/>
      <vlc:item tid="16"/>
      <vlc:item tid="17"/>
      <vlc:item tid="18"/>
   </extension>
</playlist>