代码之家  ›  专栏  ›  技术社区  ›  CLiown

xslt-对多个值排序

  •  1
  • CLiown  · 技术社区  · 15 年前

    我已经创建了我的XSLT,但是我希望能够对数据进行排序,也添加了某种索引,这样我就可以将项目分组在一起,我遇到的困难是我要排序的节点包含多个值——ID要排序的值。

    例如,这里是我的XML:

    <item>
     <title>Item 1</title>
     <subjects>English,Maths,Science,</subjects>
     <description>Blah Blah Bah...</description>
    </item>
    <item>
     <title>Item 2</title>
     <subjects>Geography,Physical Education</subjects>
     <description>Blah Blah Bah...</description>
    </item>
    <item>
     <title>Item 3</title>
     <subjects>History, Technology</subjects>
     <description>Blah Blah Bah...</description>
    </item>
    <item>
     <title>Item 4</title>
     <subjects>Maths</subjects>
     <description>Blah Blah Bah...</description>
    </item>
    

    所以如果我排序 <subjects> 我接到命令:

    English,Maths,Science,
    Geography,Physical Education
    History, Technology
    Maths
    

    但是我想要这种输出:

    English
    Geography
    History
    Maths
    Maths
    Physical Education
    Science
    Technology
    

    为中包含的每个主题输出XML <主题& ,所以第1项包含了数学、英语和科学的科目,所以我想将该标题和描述输出3次,因为它与所有3个科目都相关。

    在XSLT中,最好的方法是什么?

    2 回复  |  直到 15 年前
        1
  •  1
  •   Tim C    15 年前

    我认为这样做的一种方法是使用node set extension函数来进行多通处理。首先,您将遍历现有的主题节点,用逗号分割它们,以创建一组新的项目节点;每个主题一个。

    接下来,您将按主题顺序遍历这个新节点集。

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="urn:schemas-microsoft-com:xslt" extension-element-prefixes="exsl" version="1.0">
    
       <xsl:output method="text"/>
    
       <xsl:template match="/">
          <xsl:variable name="newitems">
             <xsl:for-each select="items/item">
                <xsl:call-template name="splititems">
                   <xsl:with-param name="itemtext" select="subjects"/>
                </xsl:call-template>
             </xsl:for-each>
          </xsl:variable>
          <xsl:for-each select="exsl:node-set($newitems)/item">
             <xsl:sort select="text()"/>
             <xsl:value-of select="text()"/>
             <xsl:text> </xsl:text>
          </xsl:for-each>
       </xsl:template>
    
       <xsl:template name="splititems">
          <xsl:param name="itemtext"/>
          <xsl:choose>
             <xsl:when test="contains($itemtext, ',')">
                <item>
                   <xsl:value-of select="substring-before($itemtext, ',')"/>
                </item>
                <xsl:call-template name="splititems">
                   <xsl:with-param name="itemtext" select="substring-after($itemtext, ',')"/>
                </xsl:call-template>
             </xsl:when>
             <xsl:when test="string-length($itemtext) &gt; 0">
                <item>
                   <xsl:value-of select="$itemtext"/>
                </item>
             </xsl:when>
          </xsl:choose>
       </xsl:template>
    
    </xsl:stylesheet>
    

    请注意,上面的示例使用了Microsoft的扩展函数。根据您使用的是什么XSLT处理器,您可能需要为处理器指定另一个名称空间。

    您可能还需要对主题进行一些“修剪”,因为在上面的XML示例中,逗号分隔的列表中的某个主题(技术)前面有一个空格。

        2
  •  1
  •   Peter Eisentraut    15 年前

    好吧,处理文本节点的内容实际上并不是XSLT的任务。如果可以的话,您可能应该更改表示,以便在subjects元素中添加更多的XML结构。否则,您将不得不使用XPath字符串函数编写一些非常聪明的字符串处理代码,或者可能使用基于Java的XSLT处理器,并将字符串处理转交给Java方法。这不简单。