【问题标题】:XSLT xsl:sort issueXSLT xsl:排序问题
【发布时间】:2011-04-23 03:04:40
【问题描述】:

我有一个需要排序的 XML 文件。在使用它的开发人员告诉我将 XML 更改为我拥有的具有 type=label 属性的项目之前,它工作得很好,以标记节点。 XSLT 不是很好。需要在“排序”节点上进行排序。

(简化的)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>...

【问题讨论】:

  • “落后者”的发生是由于 XSLT 引擎提供的默认匹配模板。由于您在频道模板中显式处理标题、链接和描述元素,因此您需要为它们创建空模板以吸收文本。您的一般应用模板调用是触发默认模板的原因。
  • @ewh - 你应该发表你的评论作为答案,我会投赞成票。
  • @ewh - 这些空模板是什么样的,它们去哪里了?我了解“应用模板”对 select=item 做了什么,看看它现在在做什么。我怎样才能让它根据公共的“排序”子节点对标签和项目进行排序?
  • 查看我的答案以获得更语义正确的解决方案,该解决方案依赖于标准 xsl:sort 行为。

标签: xml xslt sorting


【解决方案1】:

这个样式表:

<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>

注意:身份规则。排序channelchildss:首先是数字排序键的NaN 值。尽管这是正常行为,但直到 XSLT 2.0 才明确定义,来自 http://www.w3.org/TR/xslt20/#comparing-sort-keys

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

编辑:我不确定,但经过搜索,这也是 errata document 中 XSLT 1.0 规范的一部分:

在升序中,NaN 优先于所有 其他数值和降序 命令它跟随他们

【讨论】:

  • 非常感谢。有道理!
【解决方案2】:

XSLT 为节点提供了一个默认的匹配模板,在此输出节点的文本内容。

在您提供的 XSLT 中,您已经在通道模板中处理元素标题、链接和描述,由于您在通道模板中调用 apply-templates,您需要创建空模板来吸收它们。例如:

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

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

【讨论】:

  • 谢谢。很有帮助。开始更好地理解了。
【解决方案3】:

为了避免必须对特定“落后者”的名称进行“硬编码”,否则默认匹配模板会选择这些名称,在这种情况下,您可以添加自己的默认模板,以简单地忽略此类节点。

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

这匹配任何非特定节点,并简单地忽略它,并继续处理子节点(这样当它匹配'rss'节点时,它可以继续匹配'channel'节点)。 'channel'、'item' 和 'label' 的特定模板匹配将优先于此。

因此,如果您采用以下 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>

【讨论】:

    猜你喜欢
    • 2020-10-01
    • 2010-09-26
    • 2011-03-09
    • 1970-01-01
    • 2021-05-31
    • 2010-10-07
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多