【问题标题】:Importing Unicode XML code SQL导入 Unicode XML 代码 SQL
【发布时间】:2017-10-09 22:19:00
【问题描述】:

我正在尝试从以下网页导入 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 文件了。

非常感谢!

【问题讨论】:

    标签: sql-server xml xml-parsing sqlxml


    【解决方案1】:

    只是另一种选择

    示例

    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)
    

    退货

    【讨论】:

    • 很好的解决方案,但值得一提的是,BULK 可以处理UTF-8 而不是在v2014 SP2 之前
    • @Shnugo 嘿,你来了!很高兴知道。几年前我在银行的时候才遇到过这样的事情。
    【解决方案2】:

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

    问题出在这里,分为两个方面:

    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

    【讨论】:

      【解决方案3】:

      您可能需要在sp_OAMethod 调用中将最后一个参数更改为True。如下所示。

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

      False - 适用于 ANSI

      True - 适用于 UNICODE

      查看下面的链接并搜索 Unicode。

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

      【讨论】:

      • 我做了那个改变,但现在我得到一个 NULL 值作为我的 SELECT 语句的输出
      猜你喜欢
      • 1970-01-01
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 2015-07-27
      • 2018-02-26
      • 2013-05-26
      • 2023-03-16
      • 1970-01-01
      相关资源
      最近更新 更多