在传递给xsl:for-each之前对节点集进行排序

时间:2010-04-07 20:30:15

标签: xslt sorting

我有一种情况,循环遍历排序的节点集并在每个节点上应用模板:

<div id="contractscontainer">
  <xsl:for-each select="document">
    <xsl:sort select="content[@name='ClientName']/text()" />
    <xsl:apply-templates select="." mode="client-contract" />
  </xsl:for-each>
</div>

我想对节点集中的“第一个”5个节点做一些特殊的事情,然后渲染它们的嵌套元素。问题是它们需要的顺序与它们的排序顺序相同(因为它们在循环中)。

我计划通过使用两个xsl:for-each元素来执行此操作,每个元素都具有从集合中选择的正确节点。但是,我不能这样做,因为它们需要在之前进行排序我可以选择“第一个”5。

示例:

<div id="contractscontainer">
  <div class="first-five">
    <xsl:for-each select="document[position() < 6]">
      <xsl:sort select="content[@name='ClientName']/text()" />
      <xsl:apply-templates select="." mode="client-contract" />
    </xsl:for-each>
  </div>
  <div class="rest-of-them">
    <xsl:for-each select="document[position() > 5]">
      <xsl:sort select="content[@name='ClientName']/text()" />
      <xsl:apply-templates select="." mode="client-contract" />
    </xsl:for-each>
  </div>
</div>

我认为这不会起作用,因为我在排序之前按位置选择节点,但我不能在xsl:sort之外使用xsl:for-each

我接近这个错误吗?

编辑:我目前的解决方案是对它们进行排序并将已排序的集合存储在另一个变量中:

<xsl:variable name="sorted-docs">
  <xsl:for-each select="document">
    <xsl:sort select="content[@name='ClientName']/text()" />
    <xsl:copy-of select="." />
  </xsl:for-each>
</xsl:variable>

它有效,但有更好的方法吗?

1 个答案:

答案 0 :(得分:14)

以下是在XSLT 1.0中执行此操作的一种方法,无需使用xxx:node-set()扩展功能

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

 <xsl:template match="/*">
  <html>
   <div class="first-five">
     <xsl:apply-templates select="num">
       <xsl:sort select="." data-type="number"/>
       <xsl:with-param name="pStart" select="1"/>
       <xsl:with-param name="pEnd" select="5"/>
     </xsl:apply-templates>
   </div>
   <div class="rest-of-them">
     <xsl:apply-templates select="num">
       <xsl:sort select="." data-type="number"/>
       <xsl:with-param name="pStart" select="6"/>
     </xsl:apply-templates>
   </div>
  </html>
 </xsl:template>

 <xsl:template match="num">
  <xsl:param name="pStart"/>
  <xsl:param name="pEnd" select="999999999999"/>

  <xsl:if test="position() >= $pStart
              and
                not(position() > $pEnd)">
   <p><xsl:value-of select="."/></p>
  </xsl:if>
 </xsl:template>

</xsl:stylesheet>

对此简单XML文档应用上述转换时

<nums>
  <num>5</num>
  <num>3</num>
  <num>6</num>
  <num>8</num>
  <num>4</num>
  <num>1</num>
  <num>9</num>
  <num>2</num>
  <num>7</num>
  <num>10</num>
</nums>

生成了想要的结果

<html>
    <div class="first-five">
        <p>1</p>
        <p>2</p>
        <p>3</p>
        <p>4</p>
        <p>5</p>
    </div>
    <div class="rest-of-them">
        <p>6</p>
        <p>7</p>
        <p>8</p>
        <p>9</p>
        <p>10</p>
    </div>
</html>