2011-04-23 52 views
1

我有一个XML文件,我需要排序。工作得很好,直到开发人员告诉我将XML更改为具有type = label属性的项目以标记节点。在XSLT方面不太好。需要在“排序”节点上排序。XSLT xsl:排序问题

(简化)XML看起来是这样的:

<rss> 
    <channel> 
     <title>This is the title</title> 
     <link>http://www.mydomain.com/</link> 
     <description>The Description</description> 
     <label> 
      <title>Another Label</title> 
      <sort>4</sort> 
     </label> 
     <item> 
      <title>An Item</title> 
      <sort>2</sort> 
     </item> 
     <item> 
      <title>One Item</title> 
      <sort>3</sort> 
     </item> 
     <label> 
      <title>A Label</title> 
      <sort>1</sort> 
     </label> 
    </channel> 
</rss> 

旧的XSL(当我刚整理 '项目')看起来是这样的:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes" /> 
    <xsl:template match="channel"> 
     <rss> 
      <channel> 
       <xsl:copy-of select="title"/> 
       <xsl:copy-of select="link"/> 
       <xsl:copy-of select="description"/> 
       <xsl:apply-templates select="item"> 
        <xsl:sort select="sort" data-type="number"/> 
       </xsl:apply-templates> 
      </channel> 
     </rss> 
    </xsl:template> 

    <xsl:template match="item"> 
     <xsl:copy-of select="." /> 
    </xsl:template> 
</xsl:stylesheet> 

试过这种思维会工作,它大部分是,但我得到各种“落后者”。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" encoding="UTF-8" /> 
    <xsl:template match="channel"> 
    <rss> 
     <channel> 
     <xsl:copy-of select="title"/> 
     <xsl:copy-of select="link"/> 
     <xsl:copy-of select="description"/> 
    <xsl:apply-templates> 
     <xsl:sort select="sort"/> 
    </xsl:apply-templates> 
     </channel> 
    </rss> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:copy-of select="." /> 
    </xsl:template> 

    <xsl:template match="label"> 
    <xsl:copy-of select="." /> 
    </xsl:template> 

</xsl:stylesheet> 

的“散兵游勇”是这样的,当一切都说过和做过采用了最新的XSL:

<rss xmlns:st="http://ww2.startribune.com/rss/modules/base/"> 
    <channel> 
    <title>A Title</title> 
    <link>http://www.mydomain.com/</link> 
    <description>The Description</description> 
A Title 
http://www.mydomain.com/ 
The Description 
     <label>... 
    <item>... 
+2

由于默认的匹配模板XSLT引擎提供“零星”。由于您明确处理了通道模板中的标题,链接和描述元素,因此您需要为它们创建emptry模板来吸取文本。您的常规应用模板调用是默认模板被触发的原因。 – ewh 2011-04-23 03:30:35

+0

@ewh - 您应该将您的评论发布为答案,我会赞扬它。 – 2011-04-23 03:37:51

+0

@ewh - 这些空模板是什么样子的?它们在哪里?我了解“apply-templates”对select = item做了什么,并且看看它现在在做什么。我怎么能根据普通的“排序”子节点对标签和项目进行排序? – ropadope 2011-04-23 04:09:47

回答

3

这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="channel"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*"/> 
      <xsl:apply-templates select="node()"> 
       <xsl:sort select="sort" data-type="number"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

输出:

<rss> 
    <channel> 
     <title>This is the title</title> 
     <link>http://www.mydomain.com/</link> 
     <description>The Description</description> 
     <label> 
      <title>A Label</title> 
      <sort>1</sort> 
     </label> 
     <item> 
      <title>An Item</title> 
      <sort>2</sort> 
     </item> 
     <item> 
      <title>One Item</title> 
      <sort>3</sort> 
     </item> 
     <label> 
      <title>Another Label</title> 
      <sort>4</sort> 
     </label> 
    </channel> 
</rss> 

备注:身份规则。排序channel儿童:NaN数值排序键排在第一位。 Althought这是正常的行为,但直到XSLT 2.0,这是明确定义的,从http://www.w3.org/TR/xslt20/#comparing-sort-keys

NaN值,用于排序目的,是 认为是彼此相等, 和小于任何其他数值。

编辑:我不知道,但搜索后,这也是errata document XSLT 1.0规范的一部分:

升序NaN的所有之前其他 数值和降序 命令它跟着他们

+0

非常感谢。说得通! – ropadope 2011-04-25 23:19:34

+0

@ropadope:不客气。 – 2011-04-26 03:01:18

3

XSLT为节点默认的匹配模板,其中节点的文本内容outputed 。

在您提供的XSLT中,您已经在处理通道模板中的元素标题,链接和描述,因此您需要创建空模板来吸引它们,因为您的通道模板中的应用模板调用。例如:

<xsl:template match="title|link|description"/> 

这应该会吸引你的“落后者”。

+0

谢谢你。很有帮助。开始更好地理解。 – ropadope 2011-04-25 23:18:29

1

为了避免必须对默认匹配模板中的特定“分散器”的名称进行“硬编码”,您可以在这种情况下添加自己的默认模板,以便简单地忽略这些节点。

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

这符合任何非特定的节点,并简单地忽略它,并对其进行处理的子节点(以使得当它的“RSS”节点相匹配,则随后继续以匹配“通道”节点)。您针对'频道','项目'和'标签'的具体模板匹配将优先于此。

因此,如果你采取以下XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" encoding="UTF-8"/> 

    <xsl:template match="channel"> 
     <rss> 
     <channel> 
      <xsl:copy-of select="title"/> 
      <xsl:copy-of select="link"/> 
      <xsl:copy-of select="description"/> 
      <xsl:apply-templates> 
       <xsl:sort select="sort"/> 
      </xsl:apply-templates> 
     </channel> 
     </rss> 
    </xsl:template> 

    <xsl:template match="item"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="label"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

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

并将其应用到你的简化XML,你应该得到以下输出

<rss> 
    <channel> 
     <title>This is the title</title> 
     <link>http://www.mydomain.com/</link> 
     <description>The Description</description> 
     <label> 
     <title>A Label</title> 
     <sort>1</sort> 
     </label> 
     <item> 
     <title>An Item</title> 
     <sort>2</sort> 
     </item> 
     <item> 
     <title>One Item</title> 
     <sort>3</sort> 
     </item> 
     <label> 
     <title>Another Label</title> 
     <sort>4</sort> 
     </label> 
    </channel> 
</rss>