使用XSLT在同一列表中按字母顺序排列两个元素

时间:2011-08-31 06:01:45

标签: xml sorting xslt markup

我是XSLT的新手,所以如果我的编码草率或不必要的复杂,请耐心等待。我正在尝试创建一个歌曲列表,其中包括需要按标题按字母顺序排列的歌曲。对于一些歌曲,我列出了多种语言的标题。例如,是否可以按字母顺序按日语排序,但如果没有,则按英文标题按字母顺序排列。这是一个例子:

<music-catalogue>
    <song>
        <title>
            <romaji>Agechikuten</romaji>
            <japanese>&#25562;&#20316;&#30000;</japanese>
        </title>
    </song>
    <song>
        <title>
            <romaji>Kamigami no Uta</romaji>
            <japanese>&#31070;&#12293;&#12398;&#35433;</japanese>
            <english>Song of the Gods</english>
        </title>
        <artist>
            <e-name>Himekami</e-name>
            <j-name>&#23019;&#31070;</j-name>
            <link>&himekami;</link>
        </artist>
    </song>
    <song>
        <title>
            <english>Freedom</english>
        </title>
        <artist>
            <e-name>12 Girls Band</e-name>
            <j-name>&#22899;&#23376;&#21313;&#20108;&#20048;&#22346;</j-name>
        </artist>
    </song>
    <song>
        <title>
            <romaji>Tinsagu nu Hana</romaji>
            <japanese>&#12486;&#12451;&#12531;&#12469;&#12464;&#12396;&#33457;</japanese>
        </title>
    </song>
</music-catalogue>

目前,歌曲由romaji元素的内容显示,该元素将显示:

  • 自由
  • Agechikuten
  • Kamigami no Uta
  • Tinsagu nu Hana

自由是最重要的,因为没有要分类的罗马字标签。是否可以按照罗马字元素的内容对歌曲进行排序,但如果它不存在,请使用英语元素的内容来显示此列表:

  • Agechikuten
  • 自由
  • Kamigami no Uta
  • Tinsagu nu Hana

如果我应该提供更多信息或我的编码部分,请告诉我。谢谢!

3 个答案:

答案 0 :(得分:3)

我认为这可以通过 xsl:sort 元素实现,该元素可以与 xsl:for-each xsl:apply-templates一起使用

<xsl:sort select="concat(title/romaji, title[not(romaji)]/english)" />

所以,这意味着罗马的标题,但如果没有,那么将使用英文标题。

这是一个简单的XSLT来演示

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/music-catalogue">
      <ol>
         <xsl:apply-templates select="song">
            <xsl:sort select="concat(title/romaji, title[not(romaji)]/english)" />
         </xsl:apply-templates>
      </ol>
   </xsl:template>

   <xsl:template match="song">
      <li>
         <xsl:value-of select="concat(title/romaji, title[not(romaji)]/english)" />
      </li>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,将输出以下结果

<ol>
   <li>Agechikuten</li>
   <li>Freedom</li>
   <li>Kamigami no Uta</li>
   <li>Tinsagu nu Hana</li>
</ol>

答案 1 :(得分:1)

实现这种排序的常用方法是通过所需节点的联合

<xsl:stylesheet  version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" /> 
        </xsl:copy>
    </xsl:template>

    <xsl:template match="music-catalogue">
        <xsl:copy>
            <xsl:apply-templates select="song">
                <xsl:sort select="title/romaji | title[not(romaji)]/english"/>
            </xsl:apply-templates>
        </xsl:copy> 
    </xsl:template>

</xsl:stylesheet>

产生

<music-catalogue>
   <song>
      <title>
         <romaji>Agechikuten</romaji>
         <japanese>揚作田</japanese>
      </title>
   </song>
   <song>
      <title>
         <english>Freedom</english>
      </title>
      <artist>
         <e-name>12 Girls Band</e-name>
         <j-name>女子十二乐坊</j-name>
      </artist>
   </song>
   <song>
      <title>
         <romaji>Kamigami no Uta</romaji>
         <japanese>神々の詩</japanese>
         <english>Song of the Gods</english>
      </title>
      <artist>
         <e-name>Himekami</e-name>
         <j-name>姫神</j-name>
         <link/>
      </artist>
   </song>
   <song>
      <title>
         <romaji>Tinsagu nu Hana</romaji>
         <japanese>ティンサグぬ花</japanese>
      </title>
   </song>
</music-catalogue>

答案 2 :(得分:1)

这类似于@Tim C提出的解决方案,但是不需要使用字符串连接

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

 <xsl:template match="/*">
     <xsl:apply-templates select="song/title">
       <xsl:sort select="romaji | self::*[not(romaji)]/english"/>
     </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="title">
  <xsl:text>&#xA;</xsl:text>
  <xsl:value-of select=
   "romaji | self::*[not(romaji)]/english"/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档(稍加修改以使其格式正确 - 编辑未定义的实体引用):

<music-catalogue>
    <song>
        <title>
            <romaji>Agechikuten</romaji>
            <japanese>&#25562;&#20316;&#30000;</japanese>
        </title>
    </song>
    <song>
        <title>
            <romaji>Kamigami no Uta</romaji>
            <japanese>&#31070;&#12293;&#12398;&#35433;</japanese>
            <english>Song of the Gods</english>
        </title>
        <artist>
            <e-name>Himekami</e-name>
            <j-name>&#23019;&#31070;</j-name>
            <link>&amp;himekami;</link>
        </artist>
    </song>
    <song>
        <title>
            <english>Freedom</english>
        </title>
        <artist>
            <e-name>12 Girls Band</e-name>
            <j-name>&#22899;&#23376;&#21313;&#20108;&#20048;&#22346;</j-name>
        </artist>
    </song>
    <song>
        <title>
            <romaji>Tinsagu nu Hana</romaji>
            <japanese>&#12486;&#12451;&#12531;&#12469;&#12464;&#12396;&#33457;</japanese>
        </title>
    </song>
</music-catalogue>

产生了想要的正确结果

Agechikuten
Freedom
Kamigami no Uta
Tinsagu nu Hana

<强>解释

在此解决方案中,使用 set arithmetic:

精确表达所需的排序键
 romaji | self::*[not(romaji)]/english

其中|是XPath union 运算符。

请注意,即使english之前出现(按文档顺序排列)romaji,此解决方案也能正常运行。