我一直在研究使用<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()*"
- 帮助?
答案 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
赋值运行时当前节点的内容)。因此,排序不会更改所选元素的顺序。
您必须使用特定表达式作为排序条件,如您所发现的那样。