Ich denke, Sie können das Problem vermeiden, indem Sie leeren Text durch einen temporären Wert ersetzen, den gesamten anderen Text aktualisieren und dann den temporären Wert durch eine Null ersetzen.
Ich verstehe XPath nicht, es gibt wahrscheinlich einen viel besseren Weg, dies zu tun, aber das scheint zu funktionieren:
SELECT
--#3: Replace the temporary value with null, this keeps the start and end tag
UpdateXML(
--#2: Replace everything but the temporary value
UpdateXML(
--#1: Replace empty text with a temporary value
UpdateXML(xmlData, '/TEST/VALUE[not(text())]', '<VALUE>TEMPORARY VALUE</VALUE>')
,'/TEST/VALUE[text()!="TEMPORARY VALUE"]/text()', 'hello')
,'/TEST/VALUE[text()="TEMPORARY VALUE"]/text()', null) examle
FROM (SELECT XMLType('<TEST><VALUE>hi</VALUE><VALUE>hola</VALUE><VALUE></VALUE></TEST>') as xmlData FROM DUAL);