2014-05-15 7 views
5

Oracle 11g. Ho capito che se aggiungo NOENTITYESCAPING alla funzione XMLELEMENT, si spegne bene l'escape dell'entità. Tuttavia, quando passo il risultato a EXTRACT, l'escaping sembra tornare di nuovo.La funzione EXTRACT di Oracle infrange il NOENTITYESCAPING in XMLELEMENT?

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> 

Ora, aggiungendo 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-&gt; 
2-&gt; 
3-&gt; 
4-&gt; 
5-&gt; 

Eventuali correzioni/soluzioni alternative per mantenere il escape spento? Il manual non fornisce alcun aiuto.

risposta

11

Provare a utilizzare la funzione extractvalue(), che esclude le entità codificate invece di extract(). Ecco un esempio:

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) 

risultati:

RES     
-------------------- 
1->     
2->     
3->     
4->     
5->  

Ma l'uso di extractvalue() funzione può essere limitata dal fatto che il valore di un solo nodo può restituire. In un caso di valori di nodi multipli del pacchetto utl_i18n e unescape_reference() funzione di quel pacchetto di rinvio può essere utilizzato per le entità Unescape codificato:

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; 

Risultato:

RES     
-------------------- 
><     
><     
>< 

Sì, come utl_i18n.unescape_reference() la funzione accetta solo i valori del tipo di dati varchar2 e i tipi che possono essere convertiti implicitamente nel tipo di dati varchar2, le mani sono legate quando si tratta dell'elaborazione di grandi dimensioni "corde ". In questa situazione è possibile rivolgersi al pacchetto dbms_xmlgen e alla funzione convert() in particolare, che ha una versione sovraccaricata in grado di accettare CLOB s. Ecco un esempio:

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 

Risultato:

RES 
------------------------------------------------------ 
><><><><><><><><><><><><><><><><><><><><><><><><><> 
-- ... the rest of the CLOB 
+0

Grazie Nicola. Vedo che hai aggiornato la tua risposta mentre stavo per commentare che sto usando XMLAGG (per aggirare il limite di 4000 caratteri di LISTAGG), e che extractvalue non funzionerà con quello. Ho provato la tua raccomandazione di utl_i18n.unescape_reference, tuttavia penso che stia colpendo anche il limite di 4000 caratteri. – TrojanName

+0

Ecco la mia query corrente, che dimostra il problema: selezionare rtrim (xmlagg (xmlelement (e, id, '->'). Extract ('// text()') ordina da id) .GetClobVal(), ',') da (selezionare il livello come id da dual connect per livello <6) – TrojanName

+1

@TrojanName 'Penso che stia colpendo anche il limite di 4000 caratteri 'Sì. La funzione 'unescape_reference()' accetta i valori 'varchar2'. Per elaborare stringhe "* big *" usa la funzione 'dbms_xmlgen.convert()'. La risposta è stata aggiornata. –

Problemi correlati