I have a XML data stored in a CLOB
column and I would like to delete some nodes based on a specific condition.
Example XML Data :
<?xml version="1.0" encoding="UTF-8"?>
<payment>
<person>
<surname>Marco</surname>
<name>Gralike</name>
<salary>2345</salary>
</person>
<person>
<surname>ABC</surname>
<name>TEST</name>
<salary>1234</salary>
<person>
<surname>Tiger</surname>
<name>Scott</name>
<salary>2222</salary>
</person>
</person>
</payment>
<payment>
<person>
<surname>BertJan</surname>
<name>Meinders</name>
<salary>3456</salary>
<salary>125</salary>
</person>
<person>
<surname>XYZ</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
</payment>
<payment>
<person>
<surname>Chris</surname>
<name>Gralike</name>
<salary>4567</salary>
</person>
<person>
<surname>LMN</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
</payment>
I need a Oracle PLSQL script to delete all the person tags if it contains TEST.
Final output would be :
<?xml version="1.0" encoding="UTF-8"?>
<payment>
<person>
<surname>Marco</surname>
<name>Gralike</name>
<salary>2345</salary>
</person>
</payment>
<payment>
<person>
<surname>BertJan</surname>
<name>Meinders</name>
<salary>3456</salary>
<salary>125</salary>
</person>
</payment>
<payment>
<person>
<surname>Chris</surname>
<name>Gralike</name>
<salary>4567</salary>
</person>
</payment>
Thanks in advance.
Your provided XML doesn't have a root and can't be parsed by XML parser.
Assuming it does (say payments
) as shown below:
create table t(txt clob);
insert into t values('<?xml version="1.0" encoding="UTF-8"?>
<payments>
<payment>
<person>
<surname>Marco</surname>
<name>Gralike</name>
<salary>2345</salary>
</person>
<person>
<surname>ABC</surname>
<name>TEST</name>
<salary>1234</salary>
<person>
<surname>Tiger</surname>
<name>Scott</name>
<salary>2222</salary>
</person>
</person>
</payment>
<payment>
<person>
<surname>BertJan</surname>
<name>Meinders</name>
<salary>3456</salary>
<salary>125</salary>
</person>
<person>
<surname>XYZ</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
</payment>
<payment>
<person>
<surname>Chris</surname>
<name>Gralike</name>
<salary>4567</salary>
</person>
<person>
<surname>LMN</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
</payment>
</payments>');
You can use this:
update t
set txt = to_clob(deletexml(
xmltype(t.txt),
'//payment/person[./name[text()="TEST"]]'
));
Produces:
<?xml version="1.0" encoding="UTF-8"?>
<payments>
<payment>
<person>
<surname>Marco</surname>
<name>Gralike</name>
<salary>2345</salary>
</person>
</payment>
<payment>
<person>
<surname>BertJan</surname>
<name>Meinders</name>
<salary>3456</salary>
<salary>125</salary>
</person>
</payment>
<payment>
<person>
<surname>Chris</surname>
<name>Gralike</name>
<salary>4567</salary>
</person>
</payment>
</payments>
If you want to delete a node that doesn't have a given child, use this:
update t
set txt = to_clob(deletexml(
xmltype(t.txt),
'//payment[not(./person)]'
));
It'll delete all the payment tags that don't have a person in it.
deleteXML() has been deprecated. If possible you should use XQuery update. Also try to avoid the use of '//' if the full path is fixed.
with XML_TABLE as
(
select XMLTYPE('<?xml version="1.0" encoding="UTF-8"?>
<payments>
<payment>
<person>
<surname>Marco</surname>
<name>Gralike</name>
<salary>2345</salary>
</person>
<person>
<surname>ABC</surname>
<name>TEST</name>
<salary>1234</salary>
<person>
<surname>Tiger</surname>
<name>Scott</name>
<salary>2222</salary>
</person>
</person>
</payment>
<payment>
<person>
<surname>BertJan</surname>
<name>Meinders</name>
<salary>3456</salary>
<salary>125</salary>
</person>
<person>
<surname>XYZ</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
</payment>
<payment>
<person>
<surname>Chris</surname>
<name>Gralike</name>
<salary>4567</salary>
</person>
<person>
<surname>LMN</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
</payment>
</payments>') as XML_COLUMN from dual
)
SELECT XMLQuery(
'copy $NEWXML := $XML modify (
delete nodes $NEWXML/payments/payment/person[name[text()=$NAME]]
)
return $NEWXML'
passing XML_COLUMN as "XML",
'TEST' as "NAME"
returning CONTENT
)
from XML_TABLE
/
You can try this code snipped using the SQL Workbench at livesql.oracle.com
Thanks for the sample.
<payment>
<person>
<surname>XYZ</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
<id>person 4</id>
</payment>
If one of the node contains above data then after using deletexml i get this :
<payment>
<id>person 4</id>
</payment>
How to delete this node if it does not contain any <person>
tag ?
ie How to delete the below Node as it does not contain <person>
tag :
<payment>
<id>person 4</id>
</payment>
This works
with XML_TABLE as
(
select XMLTYPE('<?xml version="1.0" encoding="UTF-8"?>
<payments>
<payment>
<person>
<surname>XYZ</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
<id>person 4</id>
</payment>
<payment>
<id>person 5</id>
</payment>
</payments>') as XML_COLUMN from dual
)
SELECT XMLQuery(
'copy $NEWXML := $XML modify (
delete nodes $NEWXML/payments/payment[not(person)]
)
return $NEWXML'
passing XML_COLUMN as "XML",
'TEST' as "NAME"
returning CONTENT
)
from XML_TABLE
<?xml version="1.0" encoding="WINDOWS-1252"?>
<payments>
<payment>
<person>
<surname>XYZ</surname>
<name>TEST</name>
<salary>1234</salary>
</person>
<id>person 4</id>
</payment>
</payments>
SQL>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.