I have a simple query:
WITH xtbl AS (
SELECT XMLTYPE ('<a><b>1</b></a>') AS xcol
FROM DUAL
)
SELECT XMLQUERY ('copy $tmp := .
modify
insert node <c>2</c>
into $tmp/a/b
return $tmp'
PASSING xcol
RETURNING CONTENT) AS newxcol
FROM xtbl;
What I'm trying to do is to insert a node <c>
after <b>
inside the node <a>
but Oracle 12c is throwing this error:
ORA-19114: XPST0003 - error during parsing the XQuery expression:
LPX-00801: XQuery syntax error at 'EOF'
5 -
- ^
I want the output as:
NEWXCOL
-------------
<a>
<b>1</b>
<c>2</c/>
</a>
I have tried looking in Oracle Docs for a replacement of appendChildXML
and follow that example but only got the error.
I know it is very basic and I'm missing something obvious. Please help.
XMLType is a system-defined opaque type for handling XML data. It as predefined member functions on it to extract XML nodes and fragments. You can create columns of XMLType and insert XML documents into it.
The XMLTABLE SQL table function returns a table from the evaluation of XQuery expressions. XQuery expressions normally return values as a sequence, however, use the XMLTABLE function to execute XQuery expressions and return values as a table instead.
XML Identifier Length Limit – Oracle XML DB supports only XML identifiers that are 4000 characters long or shorter.
Following code should be working for 11 and 12 (deprecated):
SELECT insertXMLafter(XMLType('<a><b>1</b><c>3</c></a>'),
'/a/b', XmlType('<c>2</c>'))
FROM dual;
Same code using new XMLQuery syntax:
SELECT XMLQuery('copy $tmp := . modify insert node
<c>2</c>
after $tmp/a/b
return $tmp'
PASSING XmlType('<a><b>1</b><c>3</c></a>') RETURNING CONTENT)
FROM dual;
More details regarding XMLQuery and also the old deprecated functions can be found here: http://docs.oracle.com/database/121/ADXDB/app_depr_upd.htm#ADXDB6160
One ugly but possible way to use only one SQL query that works correctly on older and current database versions would be to use the CASE method in SQL:
WITH tbl AS
(SELECT SUBSTR(MAX(version),1,2) as ver, XMLType('<a><b>1</b><c>3</c></a>') as xcol
FROM v$instance)
SELECT
CASE WHEN ver < '12' THEN
insertXMLafter(xcol,
'/a/b', XmlType('<c>2</c>'))
ELSE
XMLQuery('copy $tmp := . modify insert node
<c>2</c>
after $tmp/a/b
return $tmp'
PASSING xcol RETURNING CONTENT)
END
FROM tbl;
Of course that won't help you if the insertXMLafter method gets removed in future releases of the database. That would produce an invalid SQL. But for now you would be good and use the right method on the right versions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With