Can't read a property value from XML - sql-server

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

Related

Read XML Value in SQL Select Statement

I'm trying to extract an XML value from a SQL Server column and put it into a SQL statement. My problem is that the documentation I've found doesn't explain how to do this if there are spaces or "" in the XML path.
I'm trying to extract the value property in the XML shown here (there is no namespace in the XML). The SQL Server column is called Settings:
<properties>
<settings hwid="stream:0.0.0">
<setting typeid="78622C19-58AE-40D4-8EEA-17351F4273B6">
<name>Codec</name>
<value>4</value>
</setting>
</settings>
</properties>
You can use OPENXML to retrieve data from xml, first create procedure like this:
CREATE PROCEDURE GetXmlValueProc
#xml NVARCHAR(max)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #hdoc INT;
EXEC sp_xml_preparedocument #hdoc OUTPUT, #xml;
DECLARE #Result NVARCHAR(50);
SELECT value
FROM
OPENXML(#hdoc, '/properties/settings/setting', 2)
WITH
(
value VARCHAR(100)
);
EXEC sp_xml_removedocument #hdoc;
END
GO
And call procedure in this way:
DECLARE #xml NVARCHAR(MAX)='<properties><settings hwid="stream:0.0.0"><setting typeid="78622C19-58AE-40D4-8EEA-17351F4273B6"><name>Codec</name><value>4</value></setting></settings></properties>'
EXEC dbo.GetXmlValueProc #xml
Even you can make procedure more generic and pass the xml path to get data.
I don't see any spaces in your XML. If you mean the various attributes, such as hwid, those are parsed separately from the node names. You can select those by prefacing with #.
I assume the type of the value node is int, if not you can change it below:
SELECT
t.Settings.value('(/properties/settings/setting/value)[1]', 'int'),
t.Settings.value('(/properties/settings/setting/#typeid)[1]', 'uniqueidentifier'),
t.Settings.value('(/properties/settings/#hwid)[1]', 'nvarchar(max)')
FROM myTable t
For reference, if you ever did have a node with a space in it: it would be encoded and a double-quote as "

Parse data from XML with namespace

I'm trying to parse the XML data coming from the SQL Server. But although I tried many ways, I could not succeed.
When I run the script it does not give an error but returns a not record
DECLARE #xmlData XML
SET #xmlData = '<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:VersionMismatch</faultcode>
<faultstring>Couldnt create SOAP message. Expecting Envelope in namespace http://schemas.xmlsoap.org/soap/envelope/, but got null </faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
'
SET #xmlData = (SELECT #xmlData.query('declare default element namespace "http://schemas.xmlsoap.org/soap/envelope/";
/Envelope/Body'))
SELECT #xmlData
SELECT b.value('(./Fault/faultcode/text())[1]', 'Varchar(50)') AS [Name]
FROM #xmlData.nodes('/Body') AS a (b)
Using WITH XMLNAMESPACES:
;WITH XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS S)
SELECT b.value('(./S:Fault/faultcode/text())[1]', 'Varchar(50)') AS [Name]
FROM #xmlData.nodes('//S:Body') AS a (b);
db<>fiddle demo

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

Select XML into a XML variable in SQL Server ignoring namespaces

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

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

Resources