Select XML into a XML variable in SQL Server ignoring namespaces - sql-server

I have an XML file which looks something like this
<?xml version="1.0" encoding="utf-8"?>
<Model format="1" heartbeat="PT2S">
lots of other nodes.
</Model>
I am doing the following before trying to shred the xml. However, I only want the Model node and its Childrens etc.
Declare #xml XML
set #xml = '<?xml version="1.0" encoding="utf-8"?>
<Model format="1" heartbeat="PT2S">
lots of other nodes.
</Model>'
How do i only get the Model Section ignoring the namespace/directive. Directive in this instance of XML.
e.g. Select #xml (after removing the namespace/directive will give me the following)
<Model format="1" heartbeat="PT2S">
lots of other nodes.
</Model>
I am using SQL Server 2014. Thanks in advance.

If I understand you correctly, you need:
Declare #xml XML
set #xml = '<?xml version="1.0" encoding="utf-8"?>
<Model format="1" heartbeat="PT2S">
lots of other nodes.
</Model>'
SELECT #xml.query('Model')

I do not quite understand what you mean:
DECLARE #xml XML=
'<?xml version="1.0" encoding="utf-8"?>
<Model format="1" heartbeat="PT2S">
<test>lots of other nodes.</test>
</Model>';
SELECT #xml;
returns
<Model format="1" heartbeat="PT2S">
<test>lots of other nodes.</test>
</Model>
You speak about namespace and directive. This you should know:
Namespace
If your XML has got a namespace, you did not show this to us.
A namespace must either
be specified (at least the default namespace xmlsn)
or you must use a wildcard *:
Directive
Your <?xml version="1.0" encoding="utf-8"?> will be omitted in any case. internally SQL Server stores XML as unicode (which was UTF-16) and you are not allowed to set your own directive to an XML. That's why the simple SELECT #xml returns without the directive.
Sometimes people have troubles with special characters, which need a N before the literal, because in this case the engine complains due to the UTF-8:
DECLARE #xml XML=
N'<?xml version="1.0" encoding="utf-8"?>
<Model>
Test
</Model>';
This just as a side note...
Read your XML
To get a result in any case you might try this:
Assuming an existing default namespace
DECLARE #xml XML=
'<?xml version="1.0" encoding="utf-8"?>
<Model xmlns="tempTest" format="1" heartbeat="PT2S">
<test>lots of other nodes.</test>
</Model>';
SELECT #xml.query('/*:Model/*');

You can use the value function. This gets the contents of the model node as nvarchar(max):
select #xml.value('/Model[1]', 'nvarchar(max)')

All nodes of Model as separate rows
Declare #xml XML;
set #xml = '<?xml version="1.0" encoding="utf-8"?>
<Model format="1" heartbeat="PT2S">
<lots/> <of/> <other/> <nodes./>
</Model>';
select t.n.query('.')
from
#xml.nodes('Model/*') t(n);

Related

Can't read a property value from XML

I'm trying to get the value from the property Success but I can't, I don't know where I'm wrong.
This is my code
DECLARE #Response VARCHAR(8000) = '<?xml version="1.0" encoding="utf-8"?>
<Result xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
<Success>true</Success>
</Result>'
DECLARE #xml TABLE (
Content XML
)
INSERT INTO #xml
SELECT CAST(#Response AS XML)
SELECT
Content.value('(/Result/Success)[1]', 'BIT')
FROM #xml
The property Success is bool type
I'm trying with different scope types (nvarchar, varchar, bit, etc..)
This is what I expecting
or
Please try the following solution.
Notable points:
It is always better to use XML data type instead of the VARCHAR(..) for XML
data.
All XML elements are bound to the default namespace even if we don't
see it explicitly. That's why we need to specify it via
XMLNAMESPACES clause.
It is always better to use text() in the XPath expressions for XML
elements for performance reasons. Peculiarity of the MS SQL Server.
It is possible to omit XML prolog declaration completely. SQL Server
doesn't store it.
SQL
DECLARE #Response XML = '<?xml version="1.0" encoding="utf-8"?>
<Result xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
<Success>true</Success>
</Result>';
DECLARE #xml TABLE (Content XML);
INSERT INTO #xml
SELECT #Response;
;WITH XMLNAMESPACES (DEFAULT 'http://tempuri.org/')
SELECT result = Content.value('(/Result/Success/text())[1]', 'BIT')
FROM #xml;
Output
result
1

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

Parse xml in SQL server using Openxml

Please let me know why my query doesn't work.
Following is my XML.
Trying to parse it in SQL Server.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<PostEDIDataToEIP xmlns="http://tempuri.org/">
<xmlRequestDetails>
<Applicant>
<ApplyData>
<RefNo>86</RefNo>
<ProfileSnapshot>
<Name>King</Name>
<ResumeHeadline>RESUME HEADLINE.......................</ResumeHeadline>
</ProfileSnapshot>
</ApplyData>
</Applicant>
</xmlRequestDetails>
</PostEDIDataToEIP>
</soap:Body>
</soap:Envelope>
set #xmlRequestDetails='Above xml'
set #xPath='/soap:Envelope/soap:Body/PostEDIDataToEIP/xmlRequestDetails/Applicant/ApplyData'
Exec sp_xml_preparedocument #XML_Hndl OUTPUT, #xmlRequestDetails
select * into #jobdetails FROM OPENXML(#XML_Hndl,#xPath,2) with (RefNo smallint)
select * from #jobdetails
set #xPath='/soap:Envelope/soap:Body/PostEDIDataToEIP/xmlRequestDetails/Applicant/ApplyData/ProfileSnapshot'
select * into #personaldetails FROM OPENXML(#XML_Hndl,#xPath,2) with (Name varchar(100), ResumeHeadline varchar(100))
select * from #personaldetails
Receiving the following error.
Msg 6603, Level 16, State 2, Procedure sp_forintegration, Line 31
XML parsing error: Reference to undeclared namespace prefix: 'soap'.
The statement has been terminated.
Msg 208, Level 16, State 0, Procedure sp_forintegration, Line 33
Invalid object name '#jobdetails'.
This xml is getting inserted into Sql server table XML column.
I feel i am doing some mistake while parsing, please let me know what can be done, or how to parse.
Thanks/Regards,
Prasanth Kumar
You need to declare the namespace prefixes when you prepare the XML document, something along the following:
SET #rootxmlns = '<root xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"/>'
Exec sp_xml_preparedocument #XML_Hndl OUTPUT, #xmlRequestDetails, #rootxmlns
See here for a more detailed example.

extract xml element in sql query

I have the following xml stored in my database table.
I am trying to extract the Productid from the xml , I have been unsuccessful.
Could you tell me what changes I need to make to make the query work ?
XML :
DECLARE #Response VARCHAR(MAX) = '<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProductId xsi:type="xsd:long" xmlns="http://nn.service.eservice_v1">30061</ProductId>
</Response>'
Sql Query :
select
CONVERT(XML,CONVERT(NVARCHAR(max),#Response)).value('(/Response/ProductId)[1]','nvarchar(500)') as ProviderId
You want to store the XML in an XML type instead of converting from varchar. If you are able to strip out all the namespace stuff, the following will work.
DECLARE #Response XML = '<Response><ProductId>30061</ProductId></Response>'
SELECT #Response.value('(//ProductId)[1]','nvarchar(500)') as ProviderId
If you are not able to strip out all the namespace stuff, then you will need to include the WITH XMLNAMESPACES clause
DECLARE #Response XML = '<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProductId xsi:type="xsd:long" xmlns="http://nn.service.eservice_v1">30061</ProductId>
</Response>'
;WITH XMLNAMESPACES ('http://nn.service.eservice_v1' as e,
'http://www.w3.org/2001/XMLSchema-instance' as xsi)
SELECT #Response.value('(/Response/e:ProductId)[1]','nvarchar(500)') as ProviderId

selecting individual xml node using SQL

I have a large XML note with many nodes.
is there a way that I can select only a single node and all of its contents from the larger XML?
i am using sql 2005
You should use the query() Method if you want to get a part of your XML.
declare #XML xml
set #XML =
'
<root>
<row1>
<value>1</value>
</row1>
<row2>
<value>2</value>
</row2>
</root>
'
select #XML.query('/root/row2')
Result:
<row2>
<value>2</value>
</row2>
If you want the value from a specific node you should use value() Method.
select #XML.value('(/root/row2/value)[1]', 'int')
Result:
2
Update:
If you want to shred your XML to multiple rows you use nodes() Method.
To get values:
declare #XML xml
set #XML =
'
<root>
<row>
<value>1</value>
</row>
<row>
<value>2</value>
</row>
</root>
'
select T.N.value('value[1]', 'int')
from #XML.nodes('/root/row') as T(N)
Result:
(No column name)
1
2
To get the entire XML:
select T.N.query('.')
from #XML.nodes('/root/row') as T(N)
Result:
(No column name)
<row><value>1</value></row>
<row><value>2</value></row>

Resources