简体   繁体   中英

sql server parse xml with namespace

I'm trying to parse the following xml to get the first tag following the s:Body tag (in this case I'm looking for the string queryEE , in other messsages with the same Envelope/Body structure it will be different)

I began playing with it with something like this:

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')

But I get the error:

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

Seems like I'm having troubles with the namespace stuff

When I try with select @x.query('/Envelope') I don't get any results at all


Thanks to the answers I got from @shnugo I could finally solve it with:

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

Declare your namespace again when using xquery for xml with namespaces.

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')

Try it like this:

--your declaration

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);

--The query

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)');

Some background:

Your XML is a bit weird looking at the namespaces... if the construction is under your control, it would be worth to start here.

There is a namespace s: to define <Envelope> and <Body> . That is fine so far., But then the element <queryEE> defines a default namespace (no prefix!) and the embedded <codeEE> defines another (but empty.) default namespace, I'm pretty sure. that this empty namespaces is created within a query by combining XMLs together...

The default namespace tells the engine, that all nodes without a specific prefix are living within this namespace. So we have to address that.

My code is using WITH XMLNAMESPACES to declare all namespaces occuring in the XML. Different to the original XML I define a prefix ( innerDflt ) for the first defualt namespace. That means, we can address <innerDflt:queryEE> . The embedded element does not need a namespace. It is living within an empty default (=> no) namespace.

All this said, I just want to point out, that you can use a wildcard too:

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

And you might even use a deep search

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

But the general advise is: Be as specific as possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM