我讨厌甚至问这个问题,因为有很多关于xsl:sort功能的例子但是我已经跟着他们而且仍然,莫名其妙地被卡住了。
我在for-each中有一种,似乎是要求。然后,我希望获取所有已排序的数据并应用模板。
以下是XML示例。我有一组日志元素和结果元素,在不同的路径上,我需要根据数字时间戳值一起排序。在这个例子中,除了最后一个datatimestamp值大于三个结果元素的元素之外,一切都已经自然地排序了,这意味着它应该出现在输出的最后。如上所述,输出将按输出XML中出现的顺序显示所有日志元素,后跟所有结果元素。
<output>
<logs>
<log logtext="Username = " loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428014" />
<log logtext="Password = " loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428027" />
<log logtext="ServerURI = " loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428042" />
<log logtext="TRACE TEST" loglevel="TRACE" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428084" />
<log logtext="DEBUG TEST" loglevel="DEBUG" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428096" />
<log logtext="INFO TEST" loglevel="INFO" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428109" />
<log logtext="WARNING TEST" loglevel="WARN" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428120" />
<log logtext="ERROR TEST" loglevel="ERROR" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428133" />
<log logtext="Post-Result INFO Test" loglevel="INFO" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428353" />
</logs>
<results>
<result name="Passed Test" resultformat="TEXT" resulttype="PASS" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428352" />
<result name="Failed Test" resultformat="TEXT" resulttype="FAIL" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428352" />
<result name="Running Processes" resultformat="TABLE" resulttype="NONE" timestamp="1/23/2012 5:04:28 PM" numerictimestamp="20120123170428352">
</result>
</results>
</output>
以下是XSL的相关部分:
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="//logs/log | //results/result">
<xsl:sort data-type="number" select="@numerictimestamp"/>
<xsl:apply-templates select="self::node()" />
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="log">
.... handle formatting of the log elements
</xsl:template>
<xsl:template match="result">
.... handle formatting of the result elements
</xsl:template>
我想这是一个范围问题,排序只适用于for-each中的单个项目,但我不知道要改变什么来解决它并获得相同的结果。除了排序之外,这个XSL给了我我想要的输出。
更新问题以包含包含答案的修改后的工作代码&amp;评论如下。由于要排序的数字太大,排序失败了。它们的时间戳值包括毫秒,具体来说是精确的,因此具有讽刺意味的是,精确度是问题的原因。也就是说,即使用较短的数字将排序放在for-each中,实际上也不会排序多个项目。
大多数使用xsl:sort的示例都在for-each中执行。我不知道你可以把它包含在apply-templates中。
以下修改正常:(请注意,为了清楚起见,我明确指定数据类型为文本,我意识到这是默认值)
<xsl:apply-templates select="//logs/log | //results/result">
<!--The data-type value for the sort MUST be text, due to rounding errors introduced
attempting to sort the numerictimestamp-->
<xsl:sort data-type="text" select="@numerictimestamp"/>
</xsl:apply-templates>
我能够保持XSL的其余部分不变。
答案 0 :(得分:5)
这样做你想要的吗?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<output>
<xsl:apply-templates select="//log | //result">
<xsl:sort select="@numerictimestamp"/>
</xsl:apply-templates>
</output>
</xsl:template>
<xsl:template match="log | result">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
我认为你是正确的,因为for-each正在将范围缩小到当前项目
正在发生的另一件事是将numerictimestamp属性转换为数字会导致舍入。
如果我这样做:
<xsl:template match="log | result">
<entry>
<number><xsl:value-of select="number(@numerictimestamp)"/></number>
<string><xsl:value-of select="@numerictimestamp"/></string>
</entry>
</xsl:template>
我明白这一点:
<entry>
<number>20120123170428132</number>
<string>20120123170428133</string>
</entry>
<entry>
<number>20120123170428352</number>
<string>20120123170428353</string>
</entry>
<entry>
<number>20120123170428352</number>
<string>20120123170428352</string>
</entry>
据我所知,XSLT编号数据类型符合IEEE 754,维基百科告诉我双精度精确到15.95位。你的号码是17位