如何在DataPower适用的XSLT中实现Long转十六进制及解析逻辑?
解决办法
针对你要把VB的Long转ANSI字符逻辑搬到DataPower XSLT里的需求,分步骤来实现:
第一步:把输入的十六进制字符串补成8位(前导补0)
不管输入的十六进制字符串长短,先补前导0凑够8位,比如输入111就变成00000111。用XSLT字符串处理就能搞定:
<xsl:variable name="hex-input" select="'111'" /> <!-- 补0到8位 --> <xsl:variable name="padded-hex" select="concat(substring('00000000', 1, 8 - string-length($hex-input)), $hex-input)" />
第二步:把8位十六进制转成64位有符号整数
如果你用的DataPower支持XSLT 2.0(更简单)
XSLT 2.0原生支持64位整数类型,结合xs:hexBinary和xs:long直接转:
<xsl:variable name="hex-binary" select="xs:hexBinary($padded-hex)" /> <xsl:variable name="signed-long" select="xs:long($hex-binary)" />
这段代码先把十六进制字符串转成二进制类型,再直接转成64位有符号整数,一步到位。
要是只能用XSLT 1.0(兼容旧版DataPower)
XSLT 1.0没原生64位整数支持,得自己写模板处理,还要考虑符号位(最高位是8-F的话就是负数)。下面是自定义模板:
<xsl:template name="hex-to-signed-long"> <xsl:param name="hex" /> <xsl:param name="pos" select="string-length($hex)" /> <xsl:param name="result" select="0" /> <xsl:if test="$pos > 0"> <xsl:variable name="char" select="substring($hex, $pos, 1)" /> <xsl:variable name="value"> <xsl:choose> <xsl:when test="$char >= '0' and $char <= '9'"><xsl:value-of select="number($char)" /></xsl:when> <xsl:when test="$char >= 'A' and $char <= 'F'"><xsl:value-of select="10 + string-length(substring('ABCDEF', 1, string-length($char) - string-length(translate($char, 'ABCDEF', ''))))" /></xsl:when> <xsl:when test="$char >= 'a' and $char <= 'f'"><xsl:value-of select="10 + string-length(substring('abcdef', 1, string-length($char) - string-length(translate($char, 'abcdef', ''))))" /></xsl:when> </xsl:choose> </xsl:variable> <xsl:call-template name="hex-to-signed-long"> <xsl:with-param name="hex" select="$hex" /> <xsl:with-param name="pos" select="$pos - 1" /> <xsl:with-param name="result" select="$result + $value * (16 ^ ($pos - 1))" /> </xsl:call-template> </xsl:if> <xsl:if test="$pos = 0"> <!-- 处理符号位:最高位字符值>=8就是负数 --> <xsl:variable name="msb" select="substring($hex, 1, 1)" /> <xsl:variable name="msb-value"> <xsl:choose> <xsl:when test="$msb >= '8' and $msb <= '9'"><xsl:value-of select="number($msb)" /></xsl:when> <xsl:when test="$msb >= 'A' and $msb <= 'F'"><xsl:value-of select="10 + string-length(substring('ABCDEF', 1, string-length($msb) - string-length(translate($msb, 'ABCDEF', ''))))" /></xsl:when> <xsl:when test="$msb >= 'a' and $msb <= 'f'"><xsl:value-of select="10 + string-length(substring('abcdef', 1, string-length($msb) - string-length(translate($msb, 'abcdef', ''))))" /></xsl:when> <xsl:otherwise><xsl:value-of select="0" /></xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <xsl:when test="$msb-value >= 8"> <!-- 负数:用补码计算 --> <xsl:value-of select="$result - (16^8)" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="$result" /> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:template>
调用模板的方式:
<xsl:variable name="signed-long"> <xsl:call-template name="hex-to-signed-long"> <xsl:with-param name="hex" select="$padded-hex" /> </xsl:call-template> </xsl:variable>
第三步:把十六进制转成ANSI字符串
其实原VB逻辑是把Long转8位十六进制后,每两位转一个ANSI字符,所以直接用补好的8位十六进制字符串分组转换更高效,不用先转Long再转回十六进制。
XSLT 2.0实现
用xs:unsignedByte转每两位十六进制为字节值,再转成字符:
<xsl:variable name="ansi-string"> <xsl:for-each select="(1,3,5,7)"> <!-- 每次取两位十六进制 --> <xsl:variable name="two-chars" select="substring($padded-hex, ., 2)" /> <!-- 转成0-255的字节值 --> <xsl:variable name="byte-value" select="xs:unsignedByte(xs:hexBinary($two-chars))" /> <!-- 转成ANSI字符 --> <xsl:value-of select="codepoints-to-string($byte-value)" /> </xsl:for-each> </xsl:variable>
XSLT 1.0实现
自定义模板处理每两位十六进制转字符:
<xsl:template name="two-hex-to-ansi"> <xsl:param name="two-hex" /> <xsl:variable name="first" select="substring($two-hex, 1, 1)" /> <xsl:variable name="second" select="substring($two-hex, 2, 1)" /> <!-- 计算第一位的十进制值 --> <xsl:variable name="first-val"> <xsl:choose> <xsl:when test="$first >= '0' and $first <= '9'"><xsl:value-of select="number($first)" /></xsl:when> <xsl:when test="$first >= 'A' and $first <= 'F'"><xsl:value-of select="10 + string-length(substring('ABCDEF', 1, string-length($first) - string-length(translate($first, 'ABCDEF', ''))))" /></xsl:when> <xsl:when test="$first >= 'a' and $first <= 'f'"><xsl:value-of select="10 + string-length(substring('abcdef', 1, string-length($first) - string-length(translate($first, 'abcdef', ''))))" /></xsl:when> </xsl:choose> </xsl:variable> <!-- 计算第二位的十进制值 --> <xsl:variable name="second-val"> <xsl:choose> <xsl:when test="$second >= '0' and $second <= '9'"><xsl:value-of select="number($second)" /></xsl:when> <xsl:when test="$second >= 'A' and $second <= 'F'"><xsl:value-of select="10 + string-length(substring('ABCDEF', 1, string-length($second) - string-length(translate($second, 'ABCDEF', ''))))" /></xsl:when> <xsl:when test="$second >= 'a' and $second <= 'f'"><xsl:value-of select="10 + string-length(substring('abcdef', 1, string-length($second) - string-length(translate($second, 'abcdef', ''))))" /></xsl:when> </xsl:choose> </xsl:variable> <!-- 计算字节值 --> <xsl:variable name="byte-val" select="$first-val * 16 + $second-val" /> <!-- 输出ANSI字符,disable-output-escaping确保转义字符生效 --> <xsl:value-of select="concat('&#x', format-number($byte-val, '00'), ';')" disable-output-escaping="yes" /> </xsl:template>
调用方式:
<xsl:variable name="ansi-string"> <xsl:call-template name="two-hex-to-ansi"> <xsl:with-param name="two-hex" select="substring($padded-hex, 1, 2)" /> </xsl:call-template> <xsl:call-template name="two-hex-to-ansi"> <xsl:with-param name="two-hex" select="substring($padded-hex, 3, 2)" /> </xsl:call-template> <xsl:call-template name="two-hex-to-ansi"> <xsl:with-param name="two-hex" select="substring($padded-hex, 5, 2)" /> </xsl:call-template> <xsl:call-template name="two-hex-to-ansi"> <xsl:with-param name="two-hex" select="substring($padded-hex, 7, 2)" /> </xsl:call-template> </xsl:variable>
完整XSLT 2.0示例
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- 输出编码设为ISO-8859-1,对应ANSI --> <xsl:output method="text" encoding="ISO-8859-1" /> <xsl:template match="/"> <!-- 输入的十六进制字符串 --> <xsl:variable name="hex-input" select="'111'" /> <!-- 补前导0到8位 --> <xsl:variable name="padded-hex" select="concat(substring('00000000', 1, 8 - string-length($hex-input)), $hex-input)" /> <!-- 转换为64位有符号整数 --> <xsl:variable name="hex-binary" select="xs:hexBinary($padded-hex)" /> <xsl:variable name="signed-long" select="xs:long($hex-binary)" /> <xsl:text>64位有符号整数:</xsl:text> <xsl:value-of select="$signed-long" /> <xsl:text> </xsl:text> <!-- 转换为ANSI字符串 --> <xsl:variable name="ansi-string"> <xsl:for-each select="(1,3,5,7)"> <xsl:variable name="two-chars" select="substring($padded-hex, ., 2)" /> <xsl:variable name="byte-value" select="xs:unsignedByte(xs:hexBinary($two-chars))" /> <xsl:value-of select="codepoints-to-string($byte-value)" /> </xsl:for-each> </xsl:variable> <xsl:text>ANSI字符串:</xsl:text> <xsl:value-of select="$ansi-string" /> </xsl:template> </xsl:stylesheet>
注意点
- 先确认你的DataPower支持的XSLT版本,优先用2.0的方案,代码更简洁。
- ANSI字符对应
ISO-8859-1编码,输出时一定要设置这个编码,不然字符可能显示乱码。 - XSLT 1.0的符号位处理要注意:8位十六进制的第一个字符如果是8到F(大小写),说明是负数,模板里会自动计算补码得到正确的64位整数。
内容的提问来源于stack exchange,提问作者Ram Adabala
相关产品推荐
相关产品推荐

