无法使用命名空间解析 XML

Unable to parse XML with namespace

正在尝试从 treasury.gov 解析 XML,它使用了两个命名空间。但是,我似乎无法从 XML 中提取数据。我的查询中没有 returns。我已尝试将名称空间添加到 preparedoc,但没有数据被 returned。命名空间是问题所在,就好像我删除了它们一样,我的代码也能正常工作。作为解决方法,使用替换来消除 "clean up" 和 XML 的名称空间。这完全消除了名称空间,直接呈现 XML。虽然这有效,但它非常丑陋,显然不是正确的解决方法。

    DECLARE @xml AS XML;
    DECLARE @idoc INT;

SET @xml = '
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="http://data.treasury.gov/Feed.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
  <title type="text">DailyTreasuryYieldCurveRateData</title>
  <id>http://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData</id>
  <updated>2019-05-30T20:27:58Z</updated>
  <link rel="self" title="DailyTreasuryYieldCurveRateData" href="DailyTreasuryYieldCurveRateData" />
  <entry>
    <id>http://data.treasury.gov/Feed.svc/DailyTreasuryYieldCurveRateData(1)</id>
    <title type="text"></title>
    <updated>2019-05-30T20:27:58Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="DailyTreasuryYieldCurveRateDatum" href="DailyTreasuryYieldCurveRateData(1)" />
    <category term="TreasuryDataWarehouseModel.DailyTreasuryYieldCurveRateDatum" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:Id m:type="Edm.Int32">1</d:Id>
        <d:NEW_DATE m:type="Edm.DateTime">1997-01-02T00:00:00</d:NEW_DATE>
        <d:BC_1MONTH m:type="Edm.Double" m:null="true" />
        <d:BC_2MONTH m:type="Edm.Double" m:null="true" />
        <d:BC_3MONTH m:type="Edm.Double">5.190000057220459</d:BC_3MONTH>
        <d:BC_6MONTH m:type="Edm.Double">5.3499999046325684</d:BC_6MONTH>
        <d:BC_1YEAR m:type="Edm.Double">5.630000114440918</d:BC_1YEAR>
        <d:BC_2YEAR m:type="Edm.Double">5.96999979019165</d:BC_2YEAR>
        <d:BC_3YEAR m:type="Edm.Double">6.130000114440918</d:BC_3YEAR>
        <d:BC_5YEAR m:type="Edm.Double">6.3000001907348633</d:BC_5YEAR>
        <d:BC_7YEAR m:type="Edm.Double">6.4499998092651367</d:BC_7YEAR>
        <d:BC_10YEAR m:type="Edm.Double">6.5399999618530273</d:BC_10YEAR>
        <d:BC_20YEAR m:type="Edm.Double">6.8499999046325684</d:BC_20YEAR>
        <d:BC_30YEAR m:type="Edm.Double">6.75</d:BC_30YEAR>
        <d:BC_30YEARDISPLAY m:type="Edm.Double">0</d:BC_30YEARDISPLAY>
      </m:properties>
    </content>
  </entry>
</feed>
'

EXEC sp_XML_PrepareDocument @iDoc OUTPUT, @xml, '<feed xml:base="http://data.treasury.gov/Feed.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:x="http://www.w3.org/2005/Atom">';

SELECT *
FROM OPENXML(@iDoc, 'feed/entry/content/m:properties/' )
WITH
(
   [Id] VARCHAR(100) 'd:Id'                                                                                             
  ,[Date] VARCHAR(100) 'd:NEW_DATE'
)


EXEC sp_xml_removedocument @iDoc

Id 和 Date 列 return 没有数据。如果我删除名称空间,它将 return 数据如预期的那样。

使用 FROM OPENXML 和存储过程来准备和删除文档的方法已经过时,不应再使用。而是使用本机 XML 方法:

你的XML

DECLARE @xml XML =
'<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="http://data.treasury.gov/Feed.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
  <title type="text">DailyTreasuryYieldCurveRateData</title>
  <id>http://data.treasury.gov/feed.svc/DailyTreasuryYieldCurveRateData</id>
  <updated>2019-05-30T20:27:58Z</updated>
  <link rel="self" title="DailyTreasuryYieldCurveRateData" href="DailyTreasuryYieldCurveRateData" />
  <entry>
    <id>http://data.treasury.gov/Feed.svc/DailyTreasuryYieldCurveRateData(1)</id>
    <title type="text"></title>
    <updated>2019-05-30T20:27:58Z</updated>
    <author>
      <name />
    </author>
    <link rel="edit" title="DailyTreasuryYieldCurveRateDatum" href="DailyTreasuryYieldCurveRateData(1)" />
    <category term="TreasuryDataWarehouseModel.DailyTreasuryYieldCurveRateDatum" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <content type="application/xml">
      <m:properties>
        <d:Id m:type="Edm.Int32">1</d:Id>
        <d:NEW_DATE m:type="Edm.DateTime">1997-01-02T00:00:00</d:NEW_DATE>
        <d:BC_1MONTH m:type="Edm.Double" m:null="true" />
        <d:BC_2MONTH m:type="Edm.Double" m:null="true" />
        <d:BC_3MONTH m:type="Edm.Double">5.190000057220459</d:BC_3MONTH>
        <d:BC_6MONTH m:type="Edm.Double">5.3499999046325684</d:BC_6MONTH>
        <d:BC_1YEAR m:type="Edm.Double">5.630000114440918</d:BC_1YEAR>
        <d:BC_2YEAR m:type="Edm.Double">5.96999979019165</d:BC_2YEAR>
        <d:BC_3YEAR m:type="Edm.Double">6.130000114440918</d:BC_3YEAR>
        <d:BC_5YEAR m:type="Edm.Double">6.3000001907348633</d:BC_5YEAR>
        <d:BC_7YEAR m:type="Edm.Double">6.4499998092651367</d:BC_7YEAR>
        <d:BC_10YEAR m:type="Edm.Double">6.5399999618530273</d:BC_10YEAR>
        <d:BC_20YEAR m:type="Edm.Double">6.8499999046325684</d:BC_20YEAR>
        <d:BC_30YEAR m:type="Edm.Double">6.75</d:BC_30YEAR>
        <d:BC_30YEARDISPLAY m:type="Edm.Double">0</d:BC_30YEARDISPLAY>
      </m:properties>
    </content>
  </entry>
</feed>';

--涉及多个命名空间。一个 xmlns 是所谓的 默认命名空间 而其他命名空间有一个前缀。您可以使用任何您喜欢的前缀,但是 - 为了便于阅读 - 我使用与原始 XML:

相同的前缀

--下面的代码将演示,如何直接读取一些top-level元素,如何使用.nodes()深入嵌套元素以及如何使用另一个.nodes()来潜入亲戚 sub-node.

WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/2005/Atom'
                          ,'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' AS m
                          ,'http://schemas.microsoft.com/ado/2007/08/dataservices' AS d
                          ,'http://data.treasury.gov/Feed.svc/' AS base )
SELECT @xml.value('(/feed/title/text())[1]','varchar(100)') AS title
      ,@xml.value('(/feed/title/@type)[1]','varchar(100)') AS title_type
      ,@xml.value('(/feed/id/text())[1]','varchar(100)') AS id
      ,@xml.value('(/feed/updated/text())[1]','datetime') AS updated --type-safe
      --pick more elements in top level
      ,ent.value('(id/text())[1]','varchar(100)') AS entry_id
      --pick more elements from entry-level
      ,prp.value('(d:Id/text())[1]','int') AS Prop_id
      --pick more elements below <m:properties>
FROM @xml.nodes('/feed/entry') A(ent)
CROSS APPLY A.ent.nodes('content/m:properties') B(prp);

--如果事先不知道属性,可以在路径中使用*和return一个通用的EAV-list:

WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/2005/Atom'
                          ,'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata' AS m
                          ,'http://schemas.microsoft.com/ado/2007/08/dataservices' AS d
                          ,'http://data.treasury.gov/Feed.svc/' AS base )
SELECT @xml.value('(/feed/title/text())[1]','varchar(100)') AS title
      ,@xml.value('(/feed/title/@type)[1]','varchar(100)') AS title_type
      ,@xml.value('(/feed/id/text())[1]','varchar(100)') AS id
      ,@xml.value('(/feed/updated/text())[1]','datetime') AS updated --type-safe
      --pick more elements in top level
      ,ent.value('(id/text())[1]','varchar(100)') AS entry_id
      --pick more elements from entry-level
      ,AllPrps.value('local-name(.)','varchar(100)') AS Prop_Name
      ,AllPrps.value('@m:type','varchar(100)') AS Prop_Value
      ,AllPrps.value('text()[1]','varchar(100)') AS Prop_Value
      --pick more elements below <m:properties>
FROM @xml.nodes('/feed/entry') A(ent)
CROSS APPLY A.ent.nodes('content/m:properties/d:*') B(AllPrps)