Is Oracle's EXTRACT function breaking the NOENTITYESCAPING in the XMLELEMENT?
escaping, extract, oracle, oracle11g, xml
Solution
Try to use `extractvalue()` function, which unescapes encoded entities, instead of `extract()`. Here is an example:
clear screen;
column res format a20;
-- depending on a situation, NOENTITYESCAPING might be dropped
select extractvalue(
xmlelement(NOENTITYESCAPING e,id,'->')
, '//text()'
) as res
from (select level as id
from dual
connect by level < 6)
Result:
RES
--------------------
1->
2->
3->
4->
5->
But the use of `extractvalue()` function may be limited by the fact that it can return value of only one node. In a case of returning values of multiple nodes the `utl_i18n` package, and `unescape_reference()` function of that package can be used to unescape encoded entities:
clear screen;
column res format a20;
select utl_i18n.unescape_reference(xmlelement(root
, xmlelement(node1, '>')
, xmlelement(node2, '<')
).extract('//text()').getstringval()
) as res
from dual
connect by level <= 3;
Result:
RES
--------------------
><
><
><
Yes, as `utl_i18n.unescape_reference()` function accepts only values of `varchar2` data type and types that can be implicitly converted to the `varchar2` data type, your hands are tied when it comes to processing large "strings". In this situation you may turn to `dbms_xmlgen` package and convert() function in particular, which has an overloaded version capable of accepting `CLOB`s. Here is an example:
select dbms_xmlgen.convert(
xmlagg(xmlelement(root
, xmlelement(node1, '>')
, xmlelement(node2, '<')
)
).extract('//text()').getclobval()
, 1) as res
from dual
connect by level <= 3000; -- 1 (second parameter of the convert() function)
-- instructs function to decode entities
Result:
RES
------------------------------------------------------
><><><><><><><><><><><><><><><><><><><><><><><><><>
-- ... the rest of the CLOB
Problem
Oracle 11g. I figured out that if I add `NOENTITYESCAPING` to the `XMLELEMENT` function, it nicely turns off entity escaping. However, when I then pass the result to `EXTRACT` the escaping seems to come back again. ``` select xmlelement(NOENTITYESCAPING e,id,'->') from (select level as id from dual connect by level < 6) XMLELEMENT(NOENTITYESCAPINGE,ID,'->') --------------------------------------- <E>1-></E> <E>2-></E> <E>3-></E> <E>4-></E> <E>5-></E> ``` Now, adding `EXTRACT`: ``` select xmlelement(NOENTITYESCAPING e,id,'->').extract('//text()') from (select level as id from dual connect by level < 6) XMLELEMENT(NOENTITYESCAPINGE,ID,'->').EXTRACT('//TEXT()') ---------------------------------------------------------- 1-> 2-> 3-> 4-> 5-> ``` Any fixes/workarounds to keep the escaping switched off? The manual gives no help.