Msg 9402, Level 16, State 1, Line 9 XML parsing: line 1, character 38, unable to switch the encoding

后端 未结 1 1836
别那么骄傲
别那么骄傲 2021-01-14 17:01

A piece of tsql code doesnt behave the same from production to Test environment. When the code below is executed on prod it brings back data

SELECT [col1xml]         


        
相关标签:
1条回答
  • 2021-01-14 17:26

    In SQL Server you should store XML in a column typed XML. This native type has a got a lot of advantages. It is much faster and has implicit validity checks.

    From your question I take, that you store your XML in NTEXT. This type is deprecated for centuries and will not be supported in future versions! You ought to change this soon!

    SQL-Server knows two kinds of strings:

    • 1 byte strings (CHAR or VARCHAR), which is extended ASCII
      Important: This is not UTF-8! Native UTF-8 support will be part of a coming version.
    • 2 byte string (NCHAR or NVARCHAR), which is UTF-16 (UCS-2)

    If the XML has a leading declaration with an encoding (in most cases this is utf-8 or utf-16) you can get into troubles.

    If the XML is stored as 2-byte-string (at least the NTEXT tells me this), the declaration has to be utf-16. With a 1-byte-string it should be utf-8.

    The best (and easiest) was to ommit the declaration completely. You do not need it. Storing the XML in the appropriate type will kill this declaration automatically.

    What you should do: Create a new column of type XML and shuffle all your XMLs to this column. Get rid of any TEXT, NTEXT and IMAGE columns you might have!

    The next step is: Be happy and enjoy the fast and easy going with the native XML type :-D

    UPDATE Differences in environment

    You write: Data between environments is different

    The error happens here:

    cast([col1xml] as xml)
    

    If your column would store the XML in the native type, you would not need a cast (which is very expensive!!) at all. But in your case this cast depends on the actual XML. As this is stored in NTEXT it is 2-byte-string. If your XML starts with a declaration stating a non-supported encoding (in most cases utf-8), this will fail.

    Try this:

    This works

    DECLARE @xml2Byte_UTF16 NVARCHAR(100)='<?xml version="1.0" encoding="utf-16"?><root>test1</root>';
    SELECT CAST(@xml2Byte_UTF16 AS XML);
    
    DECLARE @xml1Byte_UTF8 VARCHAR(100)='<?xml version="1.0" encoding="utf-8"?><root>test2</root>';
    SELECT CAST(@xml1Byte_UTF8 AS XML);
    

    This fails

    DECLARE @xml2Byte_UTF8 NVARCHAR(100)='<?xml version="1.0" encoding="utf-8"?><root>test3</root>';
    SELECT CAST(@xml2Byte_UTF8 AS XML);
    
    DECLARE @xml1Byte_UTF16 VARCHAR(100)='<?xml version="1.0" encoding="utf-16"?><root>test4</root>';
    SELECT CAST(@xml1Byte_UTF16 AS XML);
    

    Play around with VARCHAR and NVARCHAR and utf-8 and utf-16...

    0 讨论(0)
提交回复
热议问题