我试图通过包含十六进制值的元素对我的转换输出进行排序。
<xsl:sort select="Generation/Sirio/Code" data-type="number"/>
值是普通的旧十六进制:<xsl:sort select="Generation/Sirio/Code" data-type="number"/>
但它们的排序方式如下:00 01 02 ... 0A ... FF
,表示排序方法在涉及到字符时就会失败。
我该如何解决这个问题?
非常感谢!
答案 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。