xsl:按变量排序

时间:2011-01-29 00:19:51

标签: xslt

我一直在研究使用<xsl:sort>和变量对XML进行排序的线程,但仍无法让我的排序工作。这是上下文的一些XML结构:

<records>
  <record>
    <contributors>
      <authors>
        <author>Author 1</author>
        <author>Author 2</author>
      </authors>
    </contributors>
    <titles>
      <title>I'm a Title!</title>
      <secondary-title></secondary-title>
    </titles>
    <dates>
      <year>1901</year>
    </dates>
  </record>
  <record>...</record>
  <record>...</record>
</records>

这是相关的XSL:

<xsl:variable name="sortby" 
              select="contributors/authors/author[1]" as="element()*"/>
<xsl:for-each select="//record">
  <xsl:sort select="$sortby" order="ascending"/>
  [a bunch of HTML to render the records as a bibliography]
</xsl:for-each>           

如果我在变量的“select”属性中复制字符串并将其粘贴到sort中,如下所示:

<xsl:sort select="contributors/authors/author[1]" order="ascending">

然后它的工作原理。对于变量,它没有。无论有没有as="element()*" - 帮助?

我都试过了

3 个答案:

答案 0 :(得分:1)

通常无法对Xath表达式进行动态评估 - 无论是在XSLT / Xpath 1.0还是在XSLT / Xpath 2.0 中。

这就是说,如果对内容有一些限制,可以随时实现由变量引导的排序。

以下是解决您的具体问题和一类类似问题的示例:

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

 <xsl:param name="pSortName" select="'authors'"/>
 <xsl:param name="pSortPosition" select="1"/>

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

 <xsl:template match="records">
  <records>
   <xsl:apply-templates>
     <xsl:sort select=
     ".//*[name()=$pSortName]/*
             [position()=$pSortPosition]"/>
   </xsl:apply-templates>
  </records>
 </xsl:template>
</xsl:stylesheet>

在此XML文档上应用此转换时

<records>
    <record>
        <contributors>
            <authors>
                <author>X.Y.Z</author>
                <author>A.B.C</author>
            </authors>
        </contributors>
        <titles>
            <title>Title B</title>
            <secondary-title>Title AB</secondary-title>
        </titles>
        <dates>
            <year>1901</year>
        </dates>
    </record>
    <record>
        <contributors>
            <authors>
                <author>T.U.V</author>
                <author>D.E.F</author>
            </authors>
        </contributors>
        <titles>
            <title>Title A</title>
            <secondary-title>Title BA</secondary-title>
        </titles>
        <dates>
            <year>2001</year>
        </dates>
    </record>
</records>

生成了想要的,正确的结果(按第一作者排序的记录)

<records>
   <record>
      <contributors>
         <authors>
            <author>T.U.V</author>
            <author>D.E.F</author>
         </authors>
      </contributors>
      <titles>
         <title>Title A</title>
         <secondary-title>Title BA</secondary-title>
      </titles>
      <dates>
         <year>2001</year>
      </dates>
   </record>
   <record>
      <contributors>
         <authors>
            <author>X.Y.Z</author>
            <author>A.B.C</author>
         </authors>
      </contributors>
      <titles>
         <title>Title B</title>
         <secondary-title>Title AB</secondary-title>
      </titles>
      <dates>
         <year>1901</year>
      </dates>
   </record>
</records>

如果我们将参数更改为

 <xsl:param name="pSortName" select="'authors'"/>
 <xsl:param name="pSortPosition" select="2"/>

然后转换使用第二个author 作为排序键进行排序。

如果我们将参数更改为

 <xsl:param name="pSortName" select="'titles'"/>
 <xsl:param name="pSortPosition" select="1"/>

然后转换使用titles/title元素作为排序键进行排序。

如果我们将参数更改为

 <xsl:param name="pSortName" select="'titles'"/>
 <xsl:param name="pSortPosition" select="2"/>

然后转换使用titles/secondary-title元素作为排序键进行排序。

请注意:这里我们假设任何要排序的元素都有一个唯一的后代,其名称等于pSortName中指定的值。我们还假设此元素具有子元素,pSortPosition指定要用作排序键的子元素的位置。

答案 1 :(得分:1)

其他两个未提及的解决方案:

(a)许多处理器都有一个扩展名,类似于dyn:evaluate(),用于计算以字符串形式提供的XPath表达式

(b)在某些环境中,在执行样式表之前修改样式表(当然使用XSLT转换)是可行的。这允许您插入所需的任何XPath表达式。在XSLT 2.0中,您可以将排序键编写为select="my:sort(.)",然后在单独的xsl:included stylesheet模块中定义my:sort()。

我见过的另一个相关选项是使用外部实体:select =“&amp; sortkey;”,其中可以使用向XML解析器注册的EntityResolver以编程方式将实体引用重定向到不同的XPath表达式。 / p>

答案 2 :(得分:0)

您不能在select=元素的xsl:sort部分中使用变量。 XSLT specification州:

  

xsl:sort具有select属性,其值为表达式。对于要处理的每个节点,将使用该节点作为当前节点评估表达式,并将未完成排序的完整节点列表作为当前节点列表进行处理。

表达式仅一次评估,而不是您预期的两倍。您的表达式$sortby将被评估一次,以产生每次都相同的内容(实际值取决于xsl:variable赋值运行时当前节点的内容)。因此,排序不会更改所选元素的顺序。

您必须使用特定表达式作为排序条件,如您所发现的那样。