sql server parse xml with namespace
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.
SQL Server XML namespace colon
Minimal typo - in the .value()
, do not include the leading '/':
WITH XMLNAMESPACES(N'http://schemas.fortum.com/amm/delivermeterreading' AS del)
SELECT
t.file_name, t.file_created_time received_timestamp,
h.value(N'(del:MessageId)[1]', 'varchar(40)')
FROM
load.t t
OUTER APPLY
t.xml_data.nodes('/del:DeliverMeterReading/del:Header') AS m(h)
SQL Server XQuery with Default Namespace
If namespaces are not important in your use case, you could use the namespace wildcard selector *:
, which both selects nodes without and with arbitrary namespaces.
An example query could be
(/*:AffordabilityResults/*:matchlevel)[1]
The business analyst will still have to add the selector in front of every node test, but it's the same "prefix" all the time and the only error to be expected is forgetting to use it somewhere.
XPath/XQuery - getting the field with namespace attributes out as a value/query?
Thanks for adding a sample to your XML.
Might be that this does not cover all your needs, but I think you might walk this route:
Attention: I'm assuming, that there is just one occurance of any event id per XML.
Your sample mockup table. I added two rows, one having event 53 and one not.
DECLARE @xml TABLE (id int IDENTITY, switch_xml XML)
INSERT INTO @xml (switch_xml)
VALUES
('<MAIN> <!-- event 53 exists -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>53</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>different string o tet</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>')
,(N'<MAIN> <!-- no event 53 here!!! -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>50</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>different string o tet</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>');
--using parameters makes life easier
DECLARE @SearchForEvent INT = 53;
DECLARE @ChangeThisEvent INT = 56;
DECLARE @ReplaceWith VARCHAR(100)='Some replacement';
--We can use .modify()
to update the needed value
UPDATE @xml SET switch_xml.modify('replace value of (/MAIN[Secondary[event=sql:variable("@SearchForEvent")]]
/Secondary[event=sql:variable("@ChangeThisEvent")]
/myfield
/text())[1] with sql:variable("@ReplaceWith")');
--Check the result
SELECT * FROM @xml;
The first XML looks like this:
<MAIN>
<!-- event 53 exists -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>53</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>Some replacement</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>
... and the second like this
<MAIN>
<!-- no event 53 here!!! -->
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>50</event>
<myfield>string o text</myfield>
<myfield2>some other string</myfield2>
</Secondary>
<Secondary xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<event>56</event>
<myfield>different string o tet</myfield>
<myfield2>and some other other strings</myfield2>
</Secondary>
</MAIN>
The idea in short:
- We tell
.modify()
via XPath what to change - The Xpath will dive into
<MAIN>
if there is a<Secondary>
, which has a<event>
element with the value as given (=53) - if this holds true we dive below
<Main>
into<Secondary>
, searching for an element where<event>
has the other given value (=56) - If found, we can replace this with the third given value.
Parsing XML with namespaces in SQL Server
Since your top-level node <TravelItineraryReadRS>
is not part of that XML namespace, you cannot use the DEFAULT
qualifier. Instead, you have to define a XML namespace prefix, and include that in your XQuery:
;WITH XMLNAMESPACES ('http://webservices.sabre.com/sabreXML/2011/10' AS ns)
SELECT
XmLContent.value('(/TravelItineraryReadRS/ns:TravelItinerary/ns:CustomerInfo/ns:PersonName[1]/ns:GivenName)[1]', 'nvarchar(50)') AS Name
FROM
dbo.RezMonitorXMLdataTest
WHERE
locator = 'GUBXRV'
Replacing xml namespace prefixes in SQL Server with XQuery
If you would like to replace it with space
update tbl_Archive set XML.modify('delete /*:Document/*:Volume[text()]/@xmlns:sg')
Related Topics
The Difference Between Comma and Join in SQL
Stop Access from Using Wrong Identity When Appending to Linked Table on SQL Server
SQL Access How to Return Between Dates
SQL Server Foreign Key to Multiple Tables
Odd Inner Join Syntax and Encapsulation
How to Use a Calculated Column by Another Calculated Column
Sqlite Multiple Autoincrement Columns
How to Return Last Inserted (Auto Incremented) Row Id in Hsql
How to Use a Reserved Word in SQL as a Table Name
How to Run the Same Query Multiple Times Using Loop in Pl/Sql
SQL Server: Self-Reference Fk, Trigger Instead of on Delete Cascade
Ora-00936: Missing Expression Oracle
Ssrs Remove Column from Report