2009-10-08 58 views
4

我想按升序对这些元素进行排序,但用空值排序而不是第一个,这似乎是默认情况下xslt所做的。我设法做到这一点,但不知道是否有更好的方法。这是我的例子。如何将xsl按空值升序排序最后

<b> 
    <c>2</c> 
    <c>1</c> 
    <c>3</c> 
    <c></c> 
    <c>15</c> 
    <c>11</c> 
    <c></c> 
    <c>43</c> 
    <c>4</c> 
</b> 


<xsl:template match="/"> 
    <xsl:for-each select="b/c"> 
     <xsl:sort select="node() = false()"/> 
     <xsl:sort select="." data-type="number"/> 
     Row<xsl:value-of select="position()"/>:<xsl:value-of select="."/> 
    </xsl:for-each> 
</xsl:template> 

,其表明了所需的输出:我目前使用<xsl:sort select="node() = false()"/>来测试它是null,则使用排序订购null元素

Row1:1 
Row2:2 
Row3:3 
Row4:4 
Row5:11 
Row6:15 
Row7:43 
Row8: 
Row9: 

最后(空将是1,而不是null将为0,因此它会正确命令它们)。

任何人都可以提出比这更好的东西吗?

回答

4
<xsl:template match="/"> 
    <xsl:for-each select="b/c"> 
    <xsl:sort select="concat(
     substring('1', 1, boolean(text())), 
     substring('0', 1, not(boolean(text()))) 
    )" /> 
    <xsl:sort select="." data-type="number"/> 
    <xsl:text>Row</xsl:text> 
    <xsl:value-of select="position()"/> 
    <xsl:text>:</xsl:text> 
    <xsl:value-of select="."/> 
    <xsl:text>&#10;</xsl:text> 
    </xsl:for-each> 
</xsl:template> 

此:

concat(
    substring('1', 1, boolean(text())), 
    substring('0', 1, not(boolean(text()))) 
) 

或者产生 '0' 或 '1',这取决于是否存在一个子文本节点,或没有。它是两个互斥字符串的串联 - 穷人在XPath 1.0中的if/then/else。

boolean(text())产生truefalse,然后将其转换为substring()的数字。布尔值分别转换为1或0。

以上的更完整的版本是这样的:

concat(
    substring(
    $if_str, 
    1, 
    boolean($condition) * string-length($if_str) 
), 
    substring(
    $else_str, 
    1, 
    not(boolean($condition)) * string-length($else_str) 
) 
) 
+0

这是聪明的,我喜欢它。我将不得不尝试更频繁地使用它; ;-) – 2009-10-08 16:58:05

+2

这样做是将布尔值转换为1或0,以便您可以对该值进行排序。但是你*已经可以对布尔值进行排序了;他们从错误到真实。如果你只是对'not(boolean(text()))进行排序,你将首先得到非空元素,然后是空元素。 – 2009-10-09 02:38:22

+1

有趣的是,我没有想到这一点。可以简化为'boolean(text())',然后可以通过升序/降序来控制排序顺序。 – Tomalak 2009-10-09 07:07:19