I have one CLOB database column which contain a big XML : XML_CONF I usually use the function updateXML to modify specific node of the XML, it works great. But today, I have a lot of trouble with it, because the nodes I want to modify are sometimes empty, and it does not work in this case...
Example of XML with empty textValue :
<ns2:ConfigurationTree xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy">
<ns2:ConfigurableProduct ...>...
<ns2:CPNode name="cpX">...
<ns2:FormProperty name="fpX">
<ns2:SingleValuation isCommentUserChoice="false" isValueUserChoice="false" isQtyUserChoice="false">
<ns2:Value>
**<ns2:textValue/>**
</ns2:Value>
</ns2:SingleValuation>
</ns2:FormProperty>
</ns2:CPNode>
</ns2:ConfigurableProduct>
Example of XML with textValue :
<ns2:ConfigurationTree xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy">
<ns2:ConfigurableProduct ...>...
<ns2:CPNode name="cpX">...
<ns2:FormProperty name="fpX">
<ns2:SingleValuation isCommentUserChoice="false" isValueUserChoice="false" isQtyUserChoice="false">
<ns2:Value>
**<ns2:textValue>123456</ns2:textValue>**
</ns2:Value>
</ns2:SingleValuation>
</ns2:FormProperty>
</ns2:CPNode>
</ns2:ConfigurableProduct>
For example, to replace the textValue content by "78910", I tried this to handle the two cases :
update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
'//FormProperty[@name="fpX"]//Value/textValue',xmltype('<textValue>78910</textValue>'),
'//FormProperty[@name="fpX"]//Value/textValue/text()','78910',
'xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy"').getClobVal();
But the result broke the XML (no more prefix and xmlns empty in node) :
<ns2:ConfigurationTree xmlns:ns2="com.xxxx" xmlns="com.xxxx.yyyy">
<ns2:ConfigurableProduct ...>...
<ns2:CPNode name="cpX">...
<ns2:FormProperty name="fpX">
<ns2:SingleValuation isCommentUserChoice="false" isValueUserChoice="false" isQtyUserChoice="false">
<ns2:Value>
**<textValue xmlns="">78910</textValue>**
</ns2:Value>
</ns2:SingleValuation>
</ns2:FormProperty>
</ns2:CPNode>
</ns2:ConfigurableProduct>
And if I recall the same request, with a different textValue, it does not update nothing anymore after that... I think it's because the prefix is broken on the node...
I try to do it with XMLQuery (Oracle 12), but it's the same problem.
EDIT
It almost works with :
update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
'//FormProperty[@name="fpX"]//Value/textValue/text()','78910',
'//FormProperty[@name="fpX"]//Value/textValue[not(text())]',xmltype('<textValue>78910</textValue>'),
xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy"' ).getClobVal();
But in output I don't have the new ns2:textValue node, I only have :
<ns2:Value><textValue xmlns="">78910</textValue></ns2:Value>
Why does it break the ns2 prefix, and why it put an empty xmlns attribute ?
If I specify the namespace in the new node it works, but it seems useless because they are already declared in the root node :
update T_TABLE set XML_CONF = updatexml(xmltype(XML_CONF),
'//FormProperty[@name="fpX"]//Value/textValue/text()','78910',
'//FormProperty[@name="fpX"]//Value/textValue[not(text())]',xmltype('<ns2:textValue xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy">78910</ns2:textValue>'),
'xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy"' ).getClobVal();
Give :
<ns2:textValue xmlns:ns2="com.xxxx" xmlns="xxxx.yyyy">78910</ns2:textValue></ns2:Value>
You could do:
to identify either a text node or a node with no text; or if
ns2is the same as the default (from comments):db<>fiddle with your real namespace. The newly-created
textValuenode redeclaresns2but functionally that shouldn't matter.Of course, updateXML is deprecated in 12c, but you should be able to do the same thing with Xquery update. In fact that's simpler:
I've wildcarded the namespaces for simplicity (well, actually, I haven't figure out how to make it work with namespace prefixes, even if
ns2is different from default). For some reason that gets "ORA-19112: error raised during evaluation: XQuery Update connot be compiled" on both db<>fiddle and SQL Fiddle, which are both 11.20.02; but works fine on my 11.2.0.4 and 12.2.0.1 databases.You can add a check for the relevant node existing to avoid unneccessary updates.