sql server使用命名空间解析xml

时间:2019-09-26 08:11:19

标签: sql-server xml xml-namespaces

我正在尝试解析以下xml,以获取s:Body标记之后的第一个标记(在这种情况下,我正在寻找字符串queryEE,在其他具有相同Envelope / Body结构的消息中会有所不同

我开始玩类似这样的游戏:

declare @text varchar(max)

set @text = N'
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <queryEE xmlns="http://xx.gob.gcaba.xx/">
      <codeEE xmlns="">xxxx</codeEE>
    </queryEE>
  </s:Body>
</s:Envelope>'

declare @x xml

set @x = cast(@text as xml)

select @x.query('/s:Envelope')

但是我得到了错误:

Msg 2229, Level 16, State 1, Line 16
XQuery [query()]: The name "s" does not denote a namespace.

好像我遇到了名称空间问题

当我尝试使用select @x.query('/Envelope')时,我什么都没有得到


由于我从@shnugo得到的答案,我终于可以用以下方法解决它:

select @x.value('local-name((/*:Envelope/*:Body/*)[1])','nvarchar(100)')

2 个答案:

答案 0 :(得分:1)

在将xquery用于具有命名空间的xml时,再次声明您的命名空间。

declare @text varchar(max)

set @text = N'
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <queryEE xmlns="http://xx.gob.gcaba.xx/">
      <codeEE xmlns="">xxxx</codeEE>
    </queryEE>
  </s:Body>
</s:Envelope>'

declare @x xml

set @x = cast(@text as xml)

select @x.query('declare default element namespace "http://schemas.xmlsoap.org/soap/envelope/";   
    /Envelope')

答案 1 :(得分:1)

像这样尝试:

-您的声明

declare @text varchar(max)

set @text = N'
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <queryEE xmlns="http://xx.gob.gcaba.xx/">
      <codeEE xmlns="">xxxx</codeEE>
    </queryEE>
  </s:Body>
</s:Envelope>'

declare @x xml

set @x = cast(@text as xml);

-查询

WITH XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS s
                  ,'http://xx.gob.gcaba.xx/' AS innerDflt) 
select @x.value('(/s:Envelope/s:Body/innerDflt:queryEE/codeEE/text())[1]','nvarchar(100)');

一些背景:

您看XML的命名空间有点奇怪...如果构造在您的控制之下,那么值得从这里开始。

有一个命名空间s:用于定义<Envelope><Body>。到目前为止还好。但是元素<queryEE>定义了一个默认名称空间(没有前缀!),而嵌入式<codeEE>定义了另一个(但为空!)默认名称空间。我很确定,这个空的名称空间是在查询中通过将XML组合在一起而创建的。

默认名称空间告诉引擎,所有没有特定前缀的节点都位于该名称空间。所以我们必须解决这个问题。

我的代码使用WITH XMLNAMESPACES声明XML中出现的所有名称空间。与原始XML不同,我为第一个defualt命名空间定义了前缀(innerDflt)。也就是说,我们可以寻址<innerDflt:queryEE>。嵌入式元素不需要名称空间。它位于一个空的默认(=>否)命名空间中。

所有这些,我只想指出,您也可以使用通配符:

select @x.value('(/*:Envelope/*:Body/*:queryEE/*:codeEE/text())[1]','nvarchar(100)')

您甚至可以使用深度搜索

select @x.value('(//*:codeEE/text())[1]','nvarchar(100)')

但一般建议是:尽可能具体。

相关问题