sql server parse xml with namespace - sql-server

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

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

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 "

The label 'T14' has already been declared. Label names must be unique within a query batch or stored procedure

enter image description hereIncorrect syntax near '<'.
The label 'T14' has already been declared. Label names must be unique within a query batch or stored procedure.
The code follows:
DECLARE #XML AS XML
SELECT #XML = XMLData
FROM ReadXmlFile
WHERE IndexRow = #IndexRow;
Declare #Str Varchar(max)
SET #Str=(select cast(#XML as varchar(max)))
EXEC(#Str)
PRINT(#Str)
table ReadXmlFile is contains 3 column (IndexRow,XmlData,DateTime) that value of XmlData is filled by the user uploaded file
and #Str in Old StoredProcedure was:
Declare #Str Varchar(1000)
SET #Str='BULK INSERT #tbltest1
FROM ''//192.168.1.20/Softwares/' + #stfName + '/Reading/' + #FILE_NAME + '''
WITH
(
DATAFILETYPE =''char'',
Rowterminator=''\n''
--firstrow=10
)'
now i want #tbltest1 in part **SET #Str='BULK INSERT #tbltest1** fill by column XmlData from table ReadXmlFile Instead Fill by the following path '//192.168.1.20/Softwares/' + #stfName + '/Reading/' + #FILE_NAME +
this is part of the file XML:
<TestUniverseExport xmlns="http://www.omicron.at/dataexport">
<TM_Common>
<TestReportID>c522187c-2175-4b84-90b3-ebb6f854694c</TestReportID>
<TestReportOrder>1</TestReportOrder>
<Name>OMICRON Advanced Distance</Name>
<Version>2.40 </Version>
<Title>REL521-DE805.adt</Title>
<TestStartDate>1394-08-03T14:00:20+04:30</TestStartDate>
<TestEndDate>1394-08-03T14:02:45+04:30</TestEndDate>
<Offline>false</Offline>
<Overload>false</Overload>
<HWCReportOrder>0</HWCReportOrder>
<TOReportOrder>0</TOReportOrder>
<Assessment>PASSED</Assessment>
<ManualAssessment>false</ManualAssessment>
<PartiallyExecuted>false</PartiallyExecuted>
<Error>false</Error>
<TestStartMode>IMMEDIATELY</TestStartMode>
</TM_Common>
<TM_Dist>
<TestReportID>c522187c-2175-4b84-90b3-ebb6f854694c</TestReportID>
<TestReportOrder>1</TestReportOrder>
<TestModel>CONSTANT_CURRENT</TestModel>
What you show us, is not enough to answer your question properly. I must admit, I do not even see a question... And I doubt, that the message you get is really connected to this T14 within your dateTimes...
Your XML is - after adding some closing tags - perfectly okay:
DECLARE #xml XML=
N'<TestUniverseExport>
<TM_Common>
<TestReportID>c522187c-2175-4b84-90b3-ebb6f854694c</TestReportID>
<TestReportOrder>1</TestReportOrder>
<Name>OMICRON Advanced Distance</Name>
<Version>2.40 </Version>
<Title>REL521-DE805.adt</Title>
<TestStartDate>1394-08-03T14:00:20+04:30</TestStartDate>
<TestEndDate>1394-08-03T14:02:45+04:30</TestEndDate>
</TM_Common>
</TestUniverseExport>';
SELECT elmnts.value('local-name(.)','nvarchar(max)') AS ElementName
,elmnts.value('text()[1]','nvarchar(max)') AS ElementValue
FROM #xml.nodes('/TestUniverseExport/TM_Common/*') A(elmnts);
There must be something within the data, which brings up this error. Is XMLData a natively typed XML column?
And it is totally unclear what you are trying to get here:
Declare #Str Varchar(max)
SET #Str=(select cast(#XML as varchar(max)))
EXEC(#Str)
This is rather weird... Casting a XML to a string type will not result in an executable SQL-command...
Please try to add to your question and - if possible - provide a MCVE, to reproduce your issue.
UPDATE: After you edited your quesiton...
From the screenshot I take, that the table contains XML-typed values. And you try to change the old code in a way, that the XML is not taken from a file any more but directly out of that table. Correct so far?
If my assumptions are correct, this might be really trivial:
DECLARE #XML AS XML;
SELECT #XML = XMLData
FROM ReadXmlFile
WHERE IndexRow = #IndexRow;
Declare #Str Varchar(max);
SET #Str=cast(#XML as varchar(max));
The old code needed the dynamically created statement (together with EXEC() and PRINT) to load the XML from the file system. But now you have the XML directly in your table. So just take it, cast it and proceed from there...
What your own attempts did, was to execute something which was not a SQL-Command by any means...
You are executing an invalid sql query. See on how to use sql exec | execute
Wrap your query with the correct strings.
DECLARE #XML AS XML
SELECT #XML = XMLData
FROM ReadXmlFile
WHERE IndexRow = #IndexRow;
Declare #Str Varchar(max)
SET #Str='select '''+cast(#XML as varchar(max))+''''
EXEC(#Str)
PRINT(#Str)
or if you want to view it as xml.
SET #Str='select cast('''+cast(#XML as varchar(max))+''' as xml)'

Xquery delete with Xpath from sql:variable

I am having Xpath to delete from XML in an VARCHAR(MAX) variable, but XML.modify('delete '+#MyXpath) give an error ,
The argument 1 of the XML data type method "modify" must be a string
literal.
DECLARE #myXML XML,
#MyXpath VARCHAR(MAX)
-- Processing of Xpaths for components needed to remove
-- Adding those in #XpathsToRemove
SELECT TOP(1) #MyXpath = [XPATH]
FROM #XpathsToRemove
SET #myXML.modify('delete '+#MyXpath)
Is there any way to remove those components with Xpath available in #MyXpath variable ?
-- Edit Example XML
DECLARE #myXML XML ='<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Dont forget me this weekend!</body>
</note>'
,#MyXpath VARCHAR(MAX) = '//note/from'
-- There are many Xpaths and dynamically generated with some processing so I don't want to hardcode Xpath there
SET #myXML.modify('delete '+#MyXpath)
--This doesn't works too
-- SET #myXML.modify('delete "sql:variable("MyXPath")"')
SELECT #myXML
Thanks guys, I got solution by EXEC to generate dynamic queries.
Following is link that solved my issue,
How to using for loop using XQuery to delete xml nodes [duplicate]
Solution,
DECLARE #str nvarchar(MAX)
SET #str = 'SET #MyXML.modify('+char(39)+'delete '+#MyXPath+'/*'+char(39)+'); '
EXEC sp_executesql #str, N'#MyXML xml output', #MyXML output

Insert into xml in sql using modify method

I have to modify the existing xml in a table field value.
Each row value has different xml tags like
1 row.
'<root><comments><comment>comments1</comment><comment>comments2</comment></comments></root>'
2 row .
'<Users><User><Name>MAK</Name></User><User><Name>DANNY</User></Users>'
I need to add a tag <Resource>some ID</Resource>
after the root node.
like '<Users>**<Resource>some ID</Resource>**<User><Name>comments1</Name></User><User><Name>comments2</User></Users>'
I have tried with the below code .
declare #xml xml
set #xml = '<root><comments><comment>comments1</comment><comment>comments2</comment></comments></root>'
declare #Note varchar(10)
declare #insertnode nvarchar(100)
set #insertnode='commeressd'
declare #mainnode varchar(50)
set #mainnode='(//root)[1]'
set #Note = 'comment3'
SET #xml.modify('insert <Resource>{xs:string(sql:variable("#insertnode"))}</Resource> as first into {xs:string(sql:variable("#mainnode"))}')
select #xml
the expression after
into
is giving the error
XQuery [modify()]: Syntax error near '{'
..how do we specify this into expression also dynamically.
Any help would be appreciated.
You can use /*[1] to find the "first" root node where you want the insert to happen.
declare #xml xml
set #xml = '
<root>
<comments>
<comment>comments1</comment>
<comment>comments2</comment>
</comments>
</root>'
declare #insertnode nvarchar(100)
set #insertnode='ResourceID'
set #xml.modify('insert element Resource {sql:variable("#insertnode")} as first into /*[1]')
select #xml
Result:
<root>
<Resource>ResourceID</Resource>
<comments>
<comment>comments1</comment>
<comment>comments2</comment>
</comments>
</root>

Resources