导入Unicode XML代码SQL

时间:2017-10-09 22:19:01

标签: sql-server xml xml-parsing sqlxml

我正在尝试从以下网页导入XML数据:http://www.tcmb.gov.tr/kurlar/today.xml。这是一个不断更新的网页,我希望我的SQL代码获取最新的值。

如果我手动将xml文件下载到我的计算机并运行我的SQL代码,它可以正常运行:

DECLARE @xmlFile XML
SET @xmlFile = (SELECT * FROM OPENROWSET(BULK 'C:\Users\sqlfreaq\Desktop\today.xml', SINGLE_CLOB) AS xmldata)

SELECT @xmlFile.value('(Tarih_Date/Currency/ForexSelling)[1]', 'decimal(18,5)') AS DatabaseID

但是,当我尝试使用OLE存储过程导入数据时,某些Unicode字符会发生变化,因此无法解析XML。我的代码如下:

DECLARE    @url VARCHAR(300),
    @win INT,
    @hr INT,
    @xml xml



SET    @url = 'http://www.tcmb.gov.tr/kurlar/today.xml'

EXEC @hr = sp_OACreate 'WinHttp.WinHttpRequest.5.1', @win OUT
IF @hr <> 0 EXEC sp_OAGetErrorInfo @win

EXEC @hr = sp_OAMethod @win, 'Open', NULL, 'GET', @url, 'false'
IF @hr <> 0 EXEC sp_OAGetErrorInfo @win

EXEC @hr = sp_OAMethod @win, 'Send'
IF @hr <> 0 EXEC sp_OAGetErrorInfo @win


Create table #tmp(dt nvarchar(max))
insert into #tmp exec @hr =sp_OAGetProperty @win, 'ResponseText'

Select 
CAST(CAST([dt] AS VARCHAR(MAX)) AS XML) TT
from #tmp -- single column/single row.
Drop Table #tmp -- clean up

EXEC @hr = sp_OADestroy @win 
IF @hr <> 0 EXEC sp_OAGetErrorInfo @win

但是,如果我使用此代码从NON-UNICODE xml文件中获取数据(只需将代码中的网站从http://www.tcmb.gov.tr/kurlar/today.xml更改为http://www.bnr.ro/nbrfxrates.xml,它就可以工作。如何修改我的代码或方法,以便我可以使用在线XML文件。

非常感谢!

3 个答案:

答案 0 :(得分:2)

只是另一种选择

示例

exec master..xp_cmdshell 'powershell.exe Invoke-WebRequest "http://www.tcmb.gov.tr/kurlar/today.xml" -OutFile "c:\working\today.xml"',no_output

Declare @XML xml; 
Select @XML = BulkColumn FROM  OPENROWSET(BULK 'c:\working\today.xml', SINGLE_BLOB) x; 

Select [CrossOrder]      = lvl1.n.value('@CrossOrder'       ,'int')
      ,[Kod]             = lvl1.n.value('@Kod'              ,'nvarchar(50)')  -- Set desired data tyoe
      ,[CurrencyCode]    = lvl1.n.value('@CurrencyCode'     ,'nvarchar(50)')
      ,[Unit]            = lvl1.n.value('Unit[1]'           ,'nvarchar(50)')
      ,[Isim]            = lvl1.n.value('Isim[1]'           ,'nvarchar(50)')
      ,[CurrencyName]    = lvl1.n.value('CurrencyName[1]'   ,'nvarchar(50)')
      ,[ForexBuying]     = lvl1.n.value('ForexBuying[1]'    ,'nvarchar(50)')
      ,[ForexSelling]    = lvl1.n.value('ForexSelling[1]'   ,'nvarchar(50)')
      ,[BanknoteBuying]  = lvl1.n.value('BanknoteBuying[1]' ,'nvarchar(50)')
      ,[BanknoteSelling] = lvl1.n.value('BanknoteSelling[1]','nvarchar(50)')
      ,[CrossRateUSD]    = lvl1.n.value('CrossRateUSD[1]'   ,'nvarchar(50)')
      ,[CrossRateOther]  = lvl1.n.value('CrossRateOther[1]' ,'nvarchar(50)')
 From  @XML.nodes('Tarih_Date/Currency') lvl1(n)

<强>返回

enter image description here

答案 1 :(得分:1)

这不是解决方案,只是代码失败的解释:

问题出现在这里并且是双重的:

Select 
CAST(CAST([dt] AS VARCHAR(MAX)) AS XML) TT

转换为VARCHAR而不是NVARCHAR会破坏VARCHAR's归类未涵盖的字符。

第二个问题是,您的XML以指令开头,声明编码为UTF-8。但实际数据为UTF-16(实际上是UCS-2)。

将其更改为此功能

Select 
CAST(REPLACE(CAST([dt] AS NVARCHAR(MAX)),'UTF-8','UTF-16') AS XML) TT

问题是,并非所有字符都能正确显示......

更多背景

您设置为'false'的最后一个参数并不是要声明编码(如其他地方所建议的那样),而是sync/async switch,这无济于事......

您可以将其导入VARBINARY(MAX)变量,但SQL-Server本身无法处理utf-8编码的字符串。

John的解决方案很棒,但我认为,它需要at least v2014 SP2

答案 2 :(得分:0)

您可能需要在True来电中将最后一个参数更改为sp_OAMethod。如下所示的东西。

EXEC @hr = sp_OAMethod @win, 'Open', NULL, 'GET', @url, True

错误 - 适用于ANSI

是 - 适用于UNICODE

查看以下链接并搜索Unicode。

http://notes.szemtsov.com/?p=73&print=print