I'm trying to parse a piece of XML and remove nodes that contain certain values. I know how to remove them if the value is exact, but I want to use something like a "contains".
This works to delete exactly:
update #XML set data.modify('delete //Message[text() = "customer has deleted their account"]')
But I want to delete where the "Message" node just contains the text, something like:
update #XML set data.modify('delete //Message[contains(text(), "customer")]')
However this returns the error:
XQuery [#XML.data.modify()]: 'contains()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
Try
update #XML set data.modify('delete //Message[text()][contains(.,"customer")]')
to delete the <message/> element and its contents
update #XML set data.modify('delete //Message//text()[contains(.,"customer")]')
to delete the <message/> element's contents.
Example here http://msdn.microsoft.com/en-us/library/ms178026.aspx
declare #XML xml = '
<Root>
<Sub>
<Record>
<Guid>aslkjflaksjflkasjfkljsd</Guid>
</Record>
<Record>
<Guid>opqiwuerl;kasdlfkjawop</Guid>
</Record>
</Sub>
</Root>'
declare #Guid varchar(30) = 'aslkjflaksjflkasjfkljsd'
set #XML.modify('delete /Root/Sub/Record[Guid = sql:variable("#Guid")]')
Reference
https://dba.stackexchange.com/questions/40039/how-to-return-xml-node-ordinal-or-delete-node-based-on-element-value
Related
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 "
How can the & be shown inside the XML field?
DECLARE #xml XML
SET #xml = (SELECT 'test&test' AS xml_entity
FOR XML PATH('xml_merge'),TYPE)
SELECT #xml
The result is showing a &
<xml_merge> <xml_entity>test&test</xml_entity> </xml_merge>
I also tried with CDATA tag but that didn't solve it:
DECLARE #xml XML
SET #xml = (SELECT '<![CDATA[test&test]]>' AS xml_entity
FOR XML PATH('xml_merge'),TYPE)
SELECT #xml
<xml_merge>
<xml_entity><![CDATA[test&test]]></xml_entity>
</xml_merge>
How to handle this? I need to show the & instead of &
Expected result
<xml_merge> <xml_entity>test&test</xml_entity> </xml_merge>
Ampersand is a special character in XML. That's why it requires its entity &
Please try the following SQL. It will show you that after the SELECT ... as a VARCHAR(), the entity is gone. It remains as such just inside the XML data type.
You can check it here: 2.4 Character Data and Markup
SQL
DECLARE #xml XML;
SET #xml = (SELECT 'test & test' AS xml_entity
FOR XML PATH('xml_merge'),TYPE);
SELECT #xml;
SELECT #xml.value('(/xml_merge/xml_entity/text())[1]','VARCHAR(100)') AS xml_entity;
Output
xml_entity
test & test
This seems like an X/Y problem. You want invalid XML to be returned as XML. If you want the string value then you can pull it from the XML as a value and the escape characters will be removed, however, if you want invalid XML the way you outlined it above then you will have to convert the XML to a string and then replace the escapes.
DECLARE #xml XML
SET #xml = (SELECT 'test&test' AS xml_entity
FOR XML PATH('xml_merge'),TYPE)
SELECT #xml
DECLARE #XmlBlob NVARCHAR(MAX)=CAST(#Xml AS NVARCHAR(MAX))
SELECT REPLACE(#XmlBlob,'&','&')
<xml_merge><xml_entity>test&test</xml_entity></xml_merge>
How to set a parameter in each XML nodes using SQL Server 2008?
I am new with SQL and I have XML data like this
Set #xml='<root><name>John </name><age>8</age></root>'
I need to set the value of node <name>, <age> in a parameter. For example:
Set #name='get value of node <name>'
Set #age='the value of <age>'
Is this possible? Thanks!
If I get this correctly you are getting parameters within an XML as key-value-pairs. What you try to achieve is to read the value into the fitting variable. Try it like this:
DECLARE #xml XML;
SET #xml='<root><name>John </name><age>8</age></root>';
DECLARE #name NVARCHAR(100);
DECLARE #age INT;
SET #name=#xml.value('(/root/name)[1]','nvarchar(max)');
SET #age =#xml.value('(/root/age)[1]','int');
SELECT #name,#age;
If you'd need to query the values from a variable name, you can use this:
DECLARE #nodeName NVARCHAR(100)='name';
SET #name=#xml.value('(/root/*[local-name()=sql:variable("#nodeName")])[1]','nvarchar(max)');
The central idea is to use an XQuery-expression (/root/*[local-name()=sql:variable("#nodeName")])[1] to pick the first node's value, where the element's name is like the given parameter
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>
I've been struggling with this simple piece of code without result. I'm just trying to add a new node to an XML variable.
DECLARE #XML XML;
SET #XML = '<root>
<policyData>
<txtComentario />
<idRegProducto>76</idRegProducto>
<txtDuracion>24</txtDuracion>
</policyData>
</root>';
DECLARE #NODE XML;
SET #NODE = '<newNode>10</newNode>';
SET #XML.modify
('insert sql:variable("#NODE") as first
into (/root/policyData)[0]')
SELECT #XML;
There is no errors, but the new node is not showing in the output. Is there something that I must setup first before using XML in SQL Server? Any suggestion why this is not working?
Thanks in advance!
When you use [0] you are actually saying [position()=0]. The first node has position 1 so you should change the predicate to [1] if you want to insert the new node into the first occurrence of policyData.