XSLT xsl:排序失败,数字大,data-type =“number”

时间:2012-01-23 23:27:44

标签: xslt

我讨厌甚至问这个问题,因为有很多关于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给了我我想要的输出。

EDIT1:

更新问题以包含包含答案的修改后的工作代码&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的其余部分不变。

1 个答案:

答案 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位