Pydi Pydi - 8 months ago 26
SQL Question

How to parse below xml in oracle sql

<root>
<transactiondata>
<Info>
<![CDATA[1234ABCD]]>
<Details>
<Data Name="Names">
<FirstName>A</FirstName>
<LastName>B</LastName>
<DisplayName null="true"/>
</Data>
<Data Name="Names">
<FirstName>C</FirstName>
<LastName>D</LastName>
<MiddleName>MName</MiddleName>
<DisplayName>D C</DisplayName>
</Data>
<Data Name="Address">
<Country>ABCDEF</Country>
</Data>
</Details>
</Info>
<Info>
<![CDATA[345JUHDE]]>
<Details>
<Data Name="Names">
<FirstName>AB</FirstName>
<LastName>BC</LastName>
<DisplayName>BC</DisplayName>
</Data>
<Data Name="Names">
<FirstName>CD</FirstName>
<LastName>DF</LastName>
<MiddleName null="true"/>
</Data>
<Data Name="Phone">
<PhoneNumber>7654333</PhoneNumber>
</Data>
</Details>
</Info>
</transactiondata>




The above xml was stored as clob in ClobData table,I want to parse this xml data as temporary table to join this temporary table with other different tables.

CDATA FirstName LastName DisplayName MiddleName
1234ABCD A B No Value null
1234ABCD C D D C MName
345JUHDE AB BC null No Value


Can some one please guide me how to parse clob into above format.
I tried
TABLE(xmlsequence(extract(xmltype(clobdata.data_cache), '//Info/Data[@Name="Names"]'))) tempTable
but i am not able to access cdata.

Answer Source

You can use the XMLTable function:

XMLTable maps the result of an XQuery evaluation into relational rows and columns. You can query the result returned by the function as a virtual relational table using SQL.

In this case as you have multiple name nodes under each details section, you can either use two levels of XMLTable; the first gets the CDATA text and the details, the second expands the details to get the name information:

select x1.cdata, x2.firstname, x2.middlename, x2.lastname, x2.displayname
from clobdata c
cross join xmltable (
  '/root/transactiondata/Info'
  passing xmltype(c.data_cache)
  columns cdata varchar2(10) path './text()',
    details xmltype path 'Details'
) x1
cross join xmltable (
  'Details/Data[@Name="Names"]'
  passing x1.details
  columns firstname varchar2(10) path 'FirstName',
    middlename varchar2(10) path 'MiddleName',
    lastname varchar2(10) path 'LastName',
    displayname varchar2(10) path 'DisplayName'
) x2;

CDATA      FIRSTNAME  MIDDLENAME LASTNAME   DISPLAYNAM
---------- ---------- ---------- ---------- ----------
1234ABCD   A                     B                    
1234ABCD   C          MName      D          D C       
345JUHDE   AB                    BC         BC        
345JUHDE   CD                    DF                   

or go straight to the names and then backtrack to the CDATA:

select x.cdata, x.firstname, x.middlename, x.lastname, x.displayname
from clobdata c
cross join xmltable (
  '/root/transactiondata/Info/Details/Data[@Name="Names"]'
  passing xmltype(c.data_cache)
  columns cdata varchar2(10) path './../../text()',
    firstname varchar2(10) path 'FirstName',
    middlename varchar2(10) path 'MiddleName',
    lastname varchar2(10) path 'LastName',
    displayname varchar2(10) path 'DisplayName'
) x;

CDATA      FIRSTNAME  MIDDLENAME LASTNAME   DISPLAYNAM
---------- ---------- ---------- ---------- ----------
1234ABCD   A                     B                    
1234ABCD   C          MName      D          D C       
345JUHDE   AB                    BC         BC        
345JUHDE   CD                    DF                   

Change the sizes of the columns arguments to match the actual lengths of the names you expect to see.

You can then join x (or if you prefer x1 and/or x2) - give the XMLTable's more meaningful aliases though! - to other tables as needed.

Read more about using XQuery.