Search code examples
xmloracleplsqlxmltype

From XML to list of paths in Oracle PL/SQL environment


Please suppose you have a XML file (stored, for example, in an Oracle table which has also a CLOB column):

<ALFA>
  <BETA>0123</BETA>
  <GAMMA>2345</GAMMA>
  <DELTA>
     <EPSILON>3</EPSILON>
  </DELTA>
</ALFA>

How can I produce, in output, the list of all possible paths?

/ALFA/BETA/text()
/ALFA/GAMMA/text()
/ALFA/DELTA/EPSILON/text()

My need is the following: I have to EXTRACT many information from a long XML and I have to use XMLEXTRACT with all possible paths, so I would like to know if is it possible to "dbms_output.put_line" them in an automatic way.

I need a solution which is independent from the name of the tags.

Please suppose that the XML is well-formed.

Thank you in advance for your kind help.


  • In second instance:

How can I proceed if Oracle Java Extension has not been installed, and I receive the following error?

ORA-19112: error raised during evaluation:  
ORA-06550: line 1, column 13:
PLS-00201: identifier 'SYS.DBMS_XQUERYINT' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

Please suppose that I am not DBA, and DBA don't authorize Oracle Java Extension installation.


Solution

  • You can use XMLTable to produce list of paths with XQuery.

    E.g.

    (SQLFiddle)

    with params as (
      select 
        xmltype('
          <ALFA>
            <BETA>0123</BETA>
            <GAMMA>2345</GAMMA>
            <DELTA>
               <EPSILON>3</EPSILON>
            </DELTA>
          </ALFA>
        ') p_xml
      from dual  
    )    
    select
      path_name || '/text()'
    from
      XMLTable(
        '
          for $i in $doc/descendant-or-self::*
            return <element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
        '
        passing (select p_xml from params) as "doc"
        columns path_name varchar2(4000) path '//element_path'
      )
    

    but it's a wrong way at least because it's not effective as it can.

    Just extract all values with same XQuery: (SQLFiddle)

    with params as (
      select 
        xmltype('
          <ALFA>
            <BETA>0123</BETA>
            <GAMMA>2345</GAMMA>
            <DELTA>
               <EPSILON>3</EPSILON>
            </DELTA>
          </ALFA>
        ') p_xml
      from dual  
    )    
    select
      element_path, element_text
    from
      XMLTable(
        '              
          for $i in $doc/descendant-or-self::*
            return <element>
                     <element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
                     <element_content> {$i/text()}</element_content>
                   </element>  
        '
        passing (select p_xml from params) as "doc"
        columns 
          element_path   varchar2(4000) path '//element_path',
          element_text   varchar2(4000) path '//element_content'
      )