MSSQL二进制字段XML输出异常:XSLT项目binary(16)转码问题
你遇到的这个情况其实是JDBC驱动的默认行为导致的——Microsoft SQL Server JDBC驱动在处理binary/varbinary类型字段时,默认会将二进制数据序列化为Base64编码字符串,而不是原始的十六进制格式。这也是为什么不管你用CONVERT还是CAST调整字段类型,最终输出都是ANJeGK7/SXmiRMLrEyeRwQ==(这正是你原始值0x00D25E18AEFF4979A244C2EB132791C1的Base64编码结果)。
这个需求完全可行,下面给你几种针对性的解决方案:
方案1:在SQL查询中直接转为十六进制字符串
最简单的方式是在SQL里把binary(16)字段直接转换成十六进制格式的字符串,这样JDBC会把它当作普通文本返回,不会触发Base64编码。使用CONVERT函数并指定第三个参数为2(表示不带0x前缀的十六进制输出):
SELECT CONVERT(varchar(32), AD.GGUID, 2) AS GGUID, AD.COMPNAME AS Firmen_Name_1, AD.COMPNAME2 AS Firmen_Name_2, AD.GWBRANCH AS Branche, AD.COUNTRY1 AS Land, AD.STREET1 AS Straße, AD.ZIP1 AS PLZ, AD.TOWN1 AS Ort, AD.GWSTATE1 AS Bundesland, AD.PHONEFIELDSTR10 AS Telefon_Nr, AD.MAILFIELDSTR5 AS EMail FROM dbo.TABLE_I AS CL INNER JOIN dbo.TABLE_II AS AD ON AD.GGUID = CL.TABLEGUID WHERE CL.TABLENAME = 'ADDRESS' AND CL.FIELDNAME = 'CHECKBOX' AND AD.CHECKBOX= 1 AND AD.UPDATETIMESTAMP BETWEEN DATEADD(MINUTE, -60, SYSDATETIME()) AND SYSDATETIME() ORDER BY ad.GGUID DESC
如果需要保留0x前缀,把第三个参数改成1即可。
方案2:在XSLT中解码Base64字符串
如果你希望保留JDBC返回的Base64格式,也可以在XSLT中直接解码成十六进制值。如果你的XSLT处理器支持XSLT 2.0及以上版本,可以使用内置的类型转换函数:
假设你的GGUID节点返回的是Base64字符串,在输出时可以这样处理:
<xsl:template match="/"> <root> <statement format="yyyy-MM-dd' 'hh:mm" resulttag="object_II" timezone="UTC"> <sql> -- 这里用原始的SQL查询即可 SELECT AD.GGUID, AD.COMPNAME AS Firmen_Name_1, AD.COMPNAME2 AS Firmen_Name_2, AD.GWBRANCH AS Branche, AD.COUNTRY1 AS Land, AD.STREET1 AS Straße, AD.ZIP1 AS PLZ, AD.TOWN1 AS Ort, AD.GWSTATE1 AS Bundesland, AD.PHONEFIELDSTR10 AS Telefon_Nr, AD.MAILFIELDSTR5 AS EMail FROM dbo.TABLE_I AS CL inner join dbo.TABLE_II AS AD ON AD.GGUID = CL.TABLEGUID Where CL.TABLENAME = 'ADDRESS' AND CL.FIELDNAME = 'CHECKBOX' AND AD.CHECKBOX= 1 AND AD.UPDATETIMESTAMP BETWEEN DATEADD(MINUTE, -60, SYSDATETIME()) AND SYSDATETIME() Order BY ad.GGUID DESC </sql> <xsl:for-each select="object_II"> <object> <GGUID>{xs:hexBinary(xs:base64Binary(GGUID))}</GGUID> <Firmen_Name_1>{Firmen_Name_1}</Firmen_Name_1> <!-- 其他字段按原有逻辑输出 --> </object> </xsl:for-each> </statement> </root> </xsl:template>
xs:base64Binary()会把字符串解析为Base64二进制数据,再通过xs:hexBinary()转换为十六进制字符串,最终得到你想要的00D25E18AEFF4979A244C2EB132791C1格式。
方案3:调整JDBC连接属性(进阶)
如果需要在Java层面直接获取原始的字节数组,你可以修改JDBC连接URL,添加sendBinaryParametersAsStrings=false属性(确保驱动以二进制形式传输数据),然后在XSLT处理时直接操作字节数组。不过这种方式需要你的XSLT处理器支持直接处理字节类型数据,相对前两种方案复杂度更高,一般推荐前两种更直接的方式。
总结一下,你的需求完全可以实现,选择哪种方案取决于你是否需要在后续流程中保留二进制数据,还是只需要十六进制字符串格式。
内容的提问来源于stack exchange,提问作者NvrKill

