【发布时间】:2018-11-02 17:09:29
【问题描述】:
我正在尝试在 SQL Server 2016 中创建一个存储过程,它将以前转换为 Varbinary 的 XML 转换回 XML,但在转换时出现“非法 XML 字符”错误。我找到了一种似乎可行的解决方法,但我实际上无法弄清楚它为什么会起作用,这让我感到不舒服。
存储过程获取在 SSIS 中转换为二进制并插入到表中的 varbinary(MAX) 列中的数据,并执行一个简单的
CAST(Column AS XML)
它工作了很长时间,当最初的 XML 开始包含 ®(注册商标)符号时,我才开始看到一个问题。
现在,当我尝试将二进制文件转换为 XML 时,出现此错误
消息 9420,第 16 层,状态 1,第 23 行
XML解析:第1行,第7个字符,非法xml字符
然而,如果我先将二进制文件转换为varchar(MAX),然后再将其转换为XML,它似乎可以正常工作。我不明白当我执行与直接转换为 XML 不同的中间 CAST 时发生了什么。我主要担心的是,我不想添加它来解决这种情况并最终产生意想不到的后果。
测试代码:
DECLARE @foo VARBINARY(MAX)
DECLARE @bar VARCHAR(MAX)
DECLARE @Nbar NVARCHAR(MAX)
--SELECT Varbinary
SET @foo = CAST( '<Test>®</Test>' AS VARBINARY(MAX))
SELECT @foo AsBinary
--select as binary as varchar
SET @bar = CAST(@foo AS VARCHAR(MAX))
SELECT @bar BinaryAsVarchar -- Correct string output
--select binary as nvarchar
SET @nbar = CAST(@foo AS NVARCHAR(MAX))
SELECT @nbar BinaryAsNvarchar -- Chinese characters
--select binary as XML
SELECT TRY_CAST(@foo AS XML) BinaryAsXML -- ILLEGAL XML character
-- SELECT CONVERT(xml, @obfoo) BinaryAsXML --ILLEGAL XML Character
--select BinaryAsVarcharAsXML
SELECT TRY_CAST(@bar AS XML) BinaryAsVarcharAsXML -- Correct Output
--select BinaryAsNVarcharAsXML
SELECT TRY_CAST(@nbar AS XML) BinaryAsNvarcharAsXML -- Chinese Characters
【问题讨论】:
-
varchar表示 ASCII,或者至少是单字节编码的文本。 ® 不在不受代码页影响的 0-127 范围内。尝试使用 nvarchar 和CAST( N'<Test>®</Test>' as varbinary(max))。nvarchar表示 UTF16 即两个字节,这就是为什么从 varchar 到 varbinary 到 nvarchar 的转换失败。 -
您为什么要进行任何这些转换?无论您想解决什么问题,混合类型都无济于事。如果您遇到编码错误,请确保始终使用
nvarchar字段、参数 和 字符串文字。 -
顺便说一句,这意味着有效的转换实际上是错误的——它们依赖于在转换为 varbinary 和返回文本时使用相同的编码
-
最后,为什么 SSIS 包将 text 存储到 varbinary 列中?这只是乞求转换问题。我怀疑最初的作者使用了
varchar,遇到了转换问题,而不是使用正确的列排序规则或切换到nvarchar,只是使用varbinary掩盖了问题。这并没有解决任何问题,只是将编码问题转移给了阅读器。只要没有非拉丁字符(这也不会导致 varchar 出现问题),它就可以工作。当添加第一个非拉丁字符时,boom,阅读器失败 -
问题的内联转换:
CAST(CAST( '<Test>®</Test>' AS VARBINARY(MAX)) AS NVARCHAR(MAX))呃,不要那样做。字符编码的基本规则是使用用于写入的编码进行读取。
标签: sql-server xml tsql casting varbinary