如何在XSLT2.0中对两个或多个UUID(十六进制)求和?
在XSLT 2.0中实现UUID数值求和并转回十六进制
要解决这个问题,我们可以把UUID当成128位的十六进制数值来处理,分四步就能搞定:先去掉UUID里的分隔符,转成大整数,求和之后再转回带标准格式的UUID。XSLT 2.0配合支持任意精度整数的处理器(比如Saxon)完全能实现,下面是具体的方案和代码:
核心思路分解
- 清理UUID格式:去掉UUID中的
-分隔符,得到纯32位十六进制字符串 - 十六进制转整数:利用XSLT的类型转换特性,把纯十六进制字符串转成支持任意精度的整数(不用担心128位数值溢出)
- 求和计算:对所有转换后的整数执行求和操作
- 整数转回UUID格式:把求和结果转回十六进制,补前导零到32位,再按照
8-4-4-4-12的标准格式添加分隔符
完整代码示例
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:local="http://example.com/local"> <!-- 自定义函数:将单个UUID转换为高精度整数 --> <xsl:function name="local:uuid-to-integer" as="xs:integer"> <xsl:param name="uuid" as="xs:string"/> <!-- 去掉分隔符后转成十六进制二进制,再转成整数 --> <xsl:sequence select="xs:integer(xs:hexBinary(replace($uuid, '-', '')))"/> </xsl:function> <!-- 自定义函数:将整数转回带标准格式的UUID --> <xsl:function name="local:integer-to-uuid" as="xs:string"> <xsl:param name="num" as="xs:integer"/> <!-- 转成大写十六进制字符串 --> <xsl:variable name="raw-hex" as="xs:string" select="upper-case(string(xs:hexBinary($num)))"/> <!-- 补前导零到32位;若超过32位则取低128位(最后32个字符) --> <xsl:variable name="padded-hex" as="xs:string"> <xsl:choose> <xsl:when test="string-length($raw-hex) < 32"> <xsl:value-of select="concat( string-join(for $i in 1 to (32 - string-length($raw-hex)) return '0', ''), $raw-hex )"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="substring($raw-hex, string-length($raw-hex) - 31, 32)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <!-- 按照UUID标准格式拼接分隔符 --> <xsl:sequence select="concat( substring($padded-hex, 1, 8), '-', substring($padded-hex, 9, 4), '-', substring($padded-hex, 13, 4), '-', substring($padded-hex, 17, 4), '-', substring($padded-hex, 21, 12) )"/> </xsl:function> <!-- 示例调用模板 --> <xsl:template match="/"> <!-- 定义需要求和的UUID列表 --> <xsl:variable name="uuid-list" as="xs:string*" select="( '005eb9ed-1347-4ca3-bb29-9bc0db64e1ab', 'f5276600-a2b6-4ff6-a90e-b31fe19dae41', '7d35fb7c-da5b-4830-b598-4f347a04dceb' )"/> <!-- 转换所有UUID为整数并求和 --> <xsl:variable name="sum-integer" as="xs:integer" select="sum(for $uuid in $uuid-list return local:uuid-to-integer($uuid))"/> <!-- 输出结果 --> <result> <original-uuids> <xsl:for-each select="$uuid-list"> <uuid><xsl:value-of select="."/></uuid> </xsl:for-each> </original-uuids> <sum-result-uuid><xsl:value-of select="local:integer-to-uuid($sum-integer)"/></sum-result-uuid> </result> </xsl:template> </xsl:stylesheet>
代码细节说明
local:uuid-to-integer函数:- 用
replace($uuid, '-', '')清除UUID中的所有分隔符,得到纯十六进制字符串 - 通过
xs:hexBinary()转成十六进制二进制类型,再自动转换为xs:integer——Saxon这类处理器支持任意精度整数,完全能处理128位的UUID数值
- 用
local:integer-to-uuid函数:- 把求和后的整数转成十六进制字符串,用
upper-case()统一格式(需要小写的话换成lower-case()即可) - 自动补前导零到32位,保证符合UUID的长度要求;如果求和结果超过128位,会自动截取低128位(最后32个字符),你也可以根据需求改成抛出错误或其他处理逻辑
- 用
substring()和concat()按照UUID的标准格式添加分隔符
- 把求和后的整数转成十六进制字符串,用
示例调用:
- 直接使用你提供的三个UUID作为测试列表,通过
sum()函数完成求和 - 最后输出原始UUID列表和求和后的UUID结果
- 直接使用你提供的三个UUID作为测试列表,通过
注意事项
- 必须使用支持XSLT 2.0且支持任意精度整数的处理器,比如Saxon HE/PE/EE,部分默认的轻量XSLT处理器可能不支持128位大整数的处理
内容的提问来源于stack exchange,提问作者Sojimanatsu
相关产品推荐
相关产品推荐

