【问题标题】:Parsing XML in a SQL Table在 SQL 表中解析 XML
【发布时间】:2018-09-27 23:12:19
【问题描述】:

我已经在这个网站和其他地方对这个主题进行了一些研究,我认为我有点接近解决方案,但我仍然遇到了一些麻烦。我将 XML 保存在一条记录中,格式化后看起来像这样(这是一个 sn-p):

<samlp:Response>
<saml:Assertion>
<saml:AttributeStatement>
     <saml:Attribute Name="Market Indicator">
        <saml:AttributeValue>SG</saml:AttributeValue>
     </saml:Attribute>
     <saml:Attribute Name="Proposed Coverage Effective Date">
        <saml:AttributeValue>12/1/2017</saml:AttributeValue>
     </saml:Attribute>
     <saml:Attribute Name="Premium Amount Total">
        <saml:AttributeValue>5.00</saml:AttributeValue>
     </saml:Attribute>
     <saml:Attribute Name="Group Identifier">
        <saml:AttributeValue>11111</saml:AttributeValue>
     </saml:Attribute>
     <saml:Attribute Name="Group Name">
        <saml:AttributeValue>Construction Company</saml:AttributeValue>
     </saml:Attribute>
     </saml:Attribute>
     <saml:Attribute Name="State">
        <saml:AttributeValue>PA</saml:AttributeValue>
     </saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>

我遇到的第一个问题是能够用空格调出属性名称:

SELECT m.c.value('@Group Identifier', 'varchar(max)') AS [Group]
FROM dbo.PaymentLog PL
outer apply 
pl.response.nodes('/Response/Assertion/AttributeStatement/Attribute') as 
m(c)


Msg 2209, Level 16, State 1, Line 84
XQuery [dbo.PaymentLog.Response.value()]: Syntax error near 'Group'

但如果我尝试一个不带空格的属性名称,我只会得到NULL 结果。

SELECT m.c.value('@State', 'varchar(max)') AS [State]
FROM dbo.PaymentLog PL
outer apply 
pl.response.nodes('/Response/Assertion/AttributeStatement/Attribute') as 
m(c)

我也尝试了以下查询,但也得到了NULL 结果:

SELECT m.c.value('data(.)', 'varchar(max)') AS [Values]
FROM dbo.PaymentLog PL
outer apply 
pl.response.nodes('/Response/Assertion/AttributeStatement/Attribute
[@Name="State"]') as m(c)

我认为我在球场上,但我找不到任何东西似乎可以解决我的 XML 的特定架构。

【问题讨论】:

  • 在 XML 中处理命名空间可能会令人困惑。看起来您的 XML 不完整(您有两个不同的名称空间,但您没有显示名称空间实际指向的内容),但您的一个解决方案可能类似于 with xmlnamespaces ('abc.com' as samlp, 'xyz.com' as saml) select m.c.value... pl.response.nodes('/samlp:Response/saml:Assertion/saml:AttributeStatement/saml:Attribute[@Name="State"]') as m(c) 其中 abc.com 和 xyz.com 是您的任何命名空间实际上是。

标签: sql-server xml parsing xml-parsing ssms


【解决方案1】:

有几件事要说:

  • 您的 XML sn-p 使用名称空间前缀(saml:samlp:)。这不仅仅是一些花哨的额外功能,而且必须声明或使用通配符
  • 显示一个 sn-p 是一个好主意(保持简短和简单),但是 - 不知道容器节点 - 很难提供最佳答案
  • 使用名称 saml:Attribute 令人困惑,因为这实际上是一个 XML 元素,而不是属性。有一个名为 Name 的属性具有不同的值
  • 此 XML 是 EAV 结构。在大多数情况下,EAV 不是最好的主意...如果这在您的控制之下,您可能会考虑改变它...
  • 此 XML 混合数据类型,没有任何提示,即预期的类型。因此,您的架构必须事先知道如何阅读此内容...
  • 日期格式12/1/2017 已本地化,具体取决于您的系统文化。一些系统将使用 12 月 1 日,其他系统将读取 1 月 12 日。始终为此使用 ISO8601!这可能在您的机器上完美运行,但在客户的系统上会出现愚蠢的错误。
  • 这样的结构下次可能会带有更多或不同的字段。你的读者一定很笼统……

    关于您的代码

  • 您尝试阅读SELECT m.c.value('@Group Identifier', 'varchar(max)') AS [Group]。您正在混合属性的 value 和属性的 name

    这里也一样:

但是如果我尝试一个没有空格的属性名,我只会得到 NULL 结果。 SELECT m.c.value('@State', 'varchar(max)') AS [State]

不,属性的nameName,而它的valueState。您将在此处使用谓词(请参阅我的代码)

您的最后一次尝试指向了正确的方向,但由于&lt;Response&gt; (可能)不是顶部节点,您将无法通过/Response 找到它。此外,您还缺少命名空间。

试试这样:

DECLARE @mockupTable TABLE(id INT IDENTITY, response XML);
INSERT INTO @mockupTable VALUES
(N'<root xmlns:saml="blah1" xmlns:samlp="blah2">
  <samlp:Response>
    <saml:Assertion>
      <saml:AttributeStatement>
        <saml:Attribute Name="Market Indicator">
          <saml:AttributeValue>SG</saml:AttributeValue>
        </saml:Attribute>
        <saml:Attribute Name="Proposed Coverage Effective Date">
          <saml:AttributeValue>12/1/2017</saml:AttributeValue>
        </saml:Attribute>
        <saml:Attribute Name="Premium Amount Total">
          <saml:AttributeValue>5.00</saml:AttributeValue>
        </saml:Attribute>
        <saml:Attribute Name="Group Identifier">
          <saml:AttributeValue>11111</saml:AttributeValue>
        </saml:Attribute>
        <saml:Attribute Name="Group Name">
          <saml:AttributeValue>Construction Company</saml:AttributeValue>
        </saml:Attribute>
        <saml:Attribute Name="State">
          <saml:AttributeValue>PA</saml:AttributeValue>
        </saml:Attribute>
      </saml:AttributeStatement>
    </saml:Assertion>
  </samlp:Response>
</root>');

--此查询使用WITH XMLNAMESPACES 正确声明命名空间(推荐!)。使用与xmlns:saml="here" 中的 xml 中给出的相同值,而不是 blah
--我使用带有两个斜杠//Response深度搜索,因为我不知道它嵌套在哪里(多深)。
--我使用.nodes()&lt;saml:Attribute&gt; 来读取您的值作为EAV 列表。

WITH XMLNAMESPACES('blah1' AS saml
                  ,'blah2' AS samlp)
SELECT attr.value(N'@Name','nvarchar(max)') AS AttributeName
      ,attr.value(N'(saml:AttributeValue/text())[1]','nvarchar(max)') AS AttributeValue
FROM @mockupTable PL
OUTER APPLY PL.response.nodes('//samlp:Response/saml:Assertion/saml:AttributeStatement/saml:Attribute') AS A(attr)

--此查询使用命名空间通配符(*: - 不推荐)
--我使用谓词将您的值输入一行
--但是你必须提前知道所有的期望值

SELECT attr.value(N'(*:Attribute[@Name="Market Indicator"]/*:AttributeValue/text())[1]','nvarchar(max)') AS [Market Indicator]
      ,attr.value(N'(*:Attribute[@Name="Proposed Coverage Effective Date"]/*:AttributeValue/text())[1]','nvarchar(max)') AS [Proposed Coverage Effective Date]
      ,attr.value(N'(*:Attribute[@Name="Premium Amount Total"]/*:AttributeValue/text())[1]','decimal(10,4)') AS [Premium Amount Total]
      ,attr.value(N'(*:Attribute[@Name="Group Identifier"]/*:AttributeValue/text())[1]','bigint') AS [Group Identifier]
      ,attr.value(N'(*:Attribute[@Name="Group Name"]/*:AttributeValue/text())[1]','nvarchar(max)') AS [Group Name]
      ,attr.value(N'(*:Attribute[@Name="State"]/*:AttributeValue/text())[1]','nvarchar(max)') AS [State]
FROM @mockupTable PL
OUTER APPLY PL.response.nodes('//*:Response/*:Assertion/*:AttributeStatement') AS A(attr)

【讨论】:

  • 感谢您的详尽回答!我理解您建议我使用的语法,但就我而言,我是从表中的字段中提取 xml。因此,我不想插入一个 xml 字符串,而是将其从表中拉出,例如:DECLARE @xml XML SET @xml = (SELECT response FROM dbo.PaymentLog PL WHERE PL.Request = 'Tuo')
  • WITH XMLNAMESPACES('?' AS saml, '?' AS samlp) SELECT b.value(N'@Name','nvarchar(max)') AS AttributeName, b.value(N'(saml:AttributeValue/text())[1]','nvarchar(max)') AS AttributeValue FROM @xml.nodes('//samlp:Response/saml:Assertion/saml:AttributeStatement/saml:Attribute') as a(b) 我对在这种情况下我的命名空间会是什么感到困惑。
猜你喜欢
  • 2013-03-18
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多