SQL Server 2014 - 使用西里尔字符解析XML

时间:2017-03-08 20:51:53

标签: sql-server character-encoding xml-parsing utf-16

我正在解析xml文件但是有西里尔字符问题:

这是存储过程的相关部分

要解析的SOAP输入:

'<?xml version="1.0"?>
<soapenv:Envelope xmlns:.......>
    <soapenv:Header>
    </soapenv:Header>
    <soapenv:Body>
        <GetResponse>
            <BuyerInfo>
              <Name>Polydoros Stoltidys</Name>
              <Street>Луговой проезд дом 4 корпус 1 квартира 12</Street>
            </BuyerInfo>
        </GetResponse>
    </soapenv:Body>
</soapenv:Envelope>'

存储过程

 CREATE PROCEDURE dbo.spXML_ParseSOAP
(
    @XML    XML
)
AS
SET NOCOUNT ON;
DECLARE @S nvarchar(max)='',
        @C  nvarchar(max)='',
        @D  nvarchar(max)=''


    SELECT 
        @C= IIF (CHARINDEX('['+T.X.value('local-name(.)', 'nvarchar(100)')+']',@C)=0, CONCAT( ISNULL(@C + ',','') , QUOTENAME(T.X.value('local-name(.)', 'nvarchar(100)'))), @C),
        @D= IIF (CHARINDEX('['+T.X.value('local-name(.)', 'nvarchar(100)')+']',@CP)=0, CONCAT( ISNULL(@D + ',N','') , '''',  T.X.value(N'text()[1]', 'nvarchar(max)'),''''), @D),
    FROM @XML.nodes('//*[count(child::*) = 0]') AS T(X)
    WHERE  T.X.value(N'local-name(.)', 'nvarchar(500)') 
    IN (select name from Customers.sys.columns where [object_id]=@O and is_identity=0)

    SET @S=N'INSERT INTO Sales.dbo.ShippingAddress ('+@C+',ShippingAddressID) VALUES ('+@D+','''+@FADR+''') 

    Print @S

问题是@S看起来像这样

INSERT INTO Sales.dbo.ShippingAddress ([Name],[Street1],ShippingAddressID) 
VALUES 
(N'Polydoros Sample',N'??????? ?????? ??? 4 ?????? 1 ???????? 12','KkQ0LhbhwXfzi+Ko1Ai6s+SDZRT2kYhYC3vM2x2TB5Y=') 

西里尔字母变成了???

我在所有输入之前放了N但问题显然是在之前:  我可以假设是在

    T.X.value(N'text()[1]', 'nvarchar(max)')

但我不知道如何解决它。

可以提出解决方案吗?

由于

2 个答案:

答案 0 :(得分:3)

您的DECLARE @XML行错了。字符串文字需要以大写N为前缀。角色正在转换为?在解释那个文字。

此外,您没有使用大写字母N作为所有字符串文字的前缀,但您至少有一个字符串文字为前缀(SET @S = N'行中的第一个字符串文字,因此其余部分为文字(VARCHAR没有N前缀)将隐式转换为NVARCHAR

以下对更新后代码的修改显示了这种行为,以及如何在输入字符串上放置N前缀(在调用存储过程之前)修复了问题:

DECLARE @XML XML = N' <!-- remove the N from the left to get all ???? for "Street"-->
            <BuyerInfo>
              <Name>Polydoros Stoltidys</Name>
              <Street>Луговой проезд дом 4 корпус 1 квартира 12</Street>
            </BuyerInfo>
';


DECLARE @S nvarchar(max)='',
        @C  nvarchar(max)='Street',
        @D  nvarchar(max)=''


    SELECT 
        @D= IIF (T.X.value('local-name(.)', 'nvarchar(100)') = N'Street',
                 T.X.value('./text()[1]', 'nvarchar(100)'),
                 @C)
    FROM @XML.nodes('//*[count(child::*) = 0]') AS T(X)

    SET @S=N'INSERT INTO Sales.dbo.ShippingAddress ('
           +  @C+',ShippingAddressID) VALUES (N'''+@D+''',''a'') '

    Print @S;

此外,SQL Server XML不会存储<?xml ... ?>声明行,因此您也可以从文字值的开头删除它。

答案 1 :(得分:1)

首先:如果这解决了你的问题,请接受srutzky的回答,这是用声明的变量解决你的初始例子的正确答案。 (但你可以投票:-))。

这只是一个展示问题的例子:

试试这个

SELECT 'Луговой проезд'
SELECT N'Луговой проезд'

现在试试这个:

CREATE PROCEDURE dbo.TestXML(@xml XML)
AS
BEGIN
    SELECT @xml;
END
GO

EXEC dbo.TestXML '<root><Street>Луговой проезд дом 4 корпус 1 квартира 12</Street></root>';

返回

<root>
  <Street>??????? ?????? ??? 4 ?????? 1 ???????? 12</Street>
</root>

这次电话会议(见前导&#34; N&#34;)

EXEC dbo.TestXML N'<root><Street>Луговой проезд дом 4 корпус 1 квартира 12</Street></root>';

返回

<root>
  <Street>Луговой проезд дом 4 корпус 1 квартира 12</Street>
</root>

Conclusio

不会在您的程序中 。在您输入SP之前,传递给存储过程的字符串是错误的。