SQL Server 2014 - 使用西里尔字符解析 XML
SQL Server 2014 - Parsing XML with Cyrillic Characters
我正在解析一个 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)')
但是不知道怎么解决
可以提出解决方案吗?
谢谢
您的 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 服务器 XML 永远不会存储 <?xml ... ?>
声明行,因此您最好将其从文字值的开头删除。
首先:如果这解决了您的问题,请接受 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>';
returns
<root>
<Street>??????? ?????? ??? 4 ?????? 1 ???????? 12</Street>
</root>
虽然这个调用(见前导"N")
EXEC dbo.TestXML N'<root><Street>Луговой проезд дом 4 корпус 1 квартира 12</Street></root>';
returns
<root>
<Street>Луговой проезд дом 4 корпус 1 квартира 12</Street>
</root>
结论
这不会发生在您的程序中。在您输入 SP 之前,您传递给存储过程的字符串是错误的。
我正在解析一个 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)')
但是不知道怎么解决
可以提出解决方案吗?
谢谢
您的 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 服务器 XML 永远不会存储 <?xml ... ?>
声明行,因此您最好将其从文字值的开头删除。
首先:如果这解决了您的问题,请接受 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>';
returns
<root>
<Street>??????? ?????? ??? 4 ?????? 1 ???????? 12</Street>
</root>
虽然这个调用(见前导"N")
EXEC dbo.TestXML N'<root><Street>Луговой проезд дом 4 корпус 1 квартира 12</Street></root>';
returns
<root>
<Street>Луговой проезд дом 4 корпус 1 квартира 12</Street>
</root>
结论
这不会发生在您的程序中。在您输入 SP 之前,您传递给存储过程的字符串是错误的。