如何在xslt中按十六进制排序?

时间:2010-06-14 12:29:07

标签: xslt sorting hex

我试图通过包含十六进制值的元素对我的转换输出进行排序。

<xsl:sort select="Generation/Sirio/Code" data-type="number"/>

值是普通的旧十六进制:<xsl:sort select="Generation/Sirio/Code" data-type="number"/>但它们的排序方式如下:00 01 02 ... 0A ... FF,表示排序方法在涉及到字符时就会失败。

我该如何解决这个问题?

非常感谢!

2 个答案:

答案 0 :(得分:2)

此转化

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

    <xsl:variable name="vZeroes"
     select="'00000000000000000000000000000000000000'"/>

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

 <xsl:template match="/*">
  <xsl:copy>
    <xsl:apply-templates select="*">
       <xsl:sort select=
         "concat(substring($vZeroes,
                           1,
                           string-length($vZeroes)
                          -
                           string-length(@hexVal)
                           ),
                  translate(@hexVal,'abcdef','ABCDEF')
                 )
         "/>
    </xsl:apply-templates>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档时:

<t>
  <x hexVal="0A"/>
  <x hexVal="0327FE"/>
  <x hexVal="ff5240"/>
  <x hexVal="1BA402"/>
  <x hexVal="C3A214"/>
</t>

会产生想要的正确结果:

<t>
   <x hexVal="0A"/>
   <x hexVal="0327FE"/>
   <x hexVal="1BA402"/>
   <x hexVal="C3A214"/>
   <x hexVal="ff5240"/>
</t>

解决方案详情

此解决方案唯一的假设是十六进制排序键的最大长度是有限的(比如20)。然后我们使用一串零,超过这个最大长度。 $vZeroes变量保存此零字符串,用于将每个排序键填充到左侧,使用零,以便所有排序键具有相同的长度。

答案 1 :(得分:1)

最简单的解决方案

只需删除data-type="number"

您的示例将按文本排序(这是默认值)。通常,简单地排序为文本可能是最佳方法。 XSLT 1.0不能很好地处理任意数据转换,如果你尝试将它用作“通用”字符串处理器,你最终将会遇到大型,复杂,难以维护的转换。

如果你排序为文本,你需要确保所有数字在左边用0填充到相同的长度。所有字母必须在相同的情况下(无论如何几乎总是如此,但如果组合来自不同来源的数据,则可能会中断。)通常,这些要求在XSLT之外很容易满足。

稍微更一般和更长的解决方案

xslt-function translate(my-xpath-expr,'abcdef','ABCDEF')可用于将混合大小写的十六进制转换为大写十六进制。通常这可能不是必需的。

如果你不知道十六进制数的长度,你可以在dimitre的解决方案中显示“0”,但是你可以经常使用更简单的技巧:

<xsl:sort select="string-length(Generation/Sirio/Code)" data-type="number"/>
<xsl:sort select="translate(Generation/Sirio/Code,'abcdef','ABCDEF')"/>

只要较小的数字永远不会比较大的数字长,这就有效。如果数字可能包含空格或以“0x”为前缀,它也可以使用。

但是,如果可能的话,最好只是确保所有数字的格式相同并按文字排序 - 尽可能使用KISS。