READING XML Master / Detail data using ORACLE PL/SQL      Sept 5th, 5th of Ramadan , 2008

The need for us at REALSOFT arises from our BI project for The  ministry of Higher Education in Oman.

All colleges and universities are supposed to submit data into the data warehouse on regular basis.

an XML transfer protocol has been agreed upon.  Our responsibility is to first design the XML file protocol then as the participants to upload (via a web screen) these files, then read the XML into Oracle database tables.

 

 

Assume that the file is called  college.xml

The master record contains the Basic college information

and the details is the student name within this college

Note that the details are nested within the Master row and indicated by the tag <row>

as can be seen in the file below

 

<?xml version="1.0" encoding="UTF-8"?>
<college>
    <master>                                                            <-------- first master row
        <id>10</id>
        <name>REALSOFT</name>
        <row>                                                                <---- first row starts
            <student_id>1</student_id>
            <student_name>Ahmad</student_name>
        </row>                                                              <--- First row ends
        <row>                                                                <--- Second row starts
            <student_id>2</student_id>           
            <student_name>Samia</student_name>
        </row>                                                               <----  second row ends                    

        <row>                                                                 <-----  nth row et....
            <student_id>3</student_id>
            <student_name>Tareq</student_name>
        </row>
    </master>                                                          <------ first master ends, this example has one master
</college>

 

The following is a PL/SQL that has been tested

It requires that you first create an ORACLE DIRECTORY called  XMLDIR

It also requires that you grant access to this DIRECTORY who shall execute the PLSQL block

It goes without saying that you should place your xml that is be read in the same DIRECTORY.

I called the file college.xml and as such you may need to change the code of you use a different name

 

The basic syntax to create ORACLE Directory is

SQL> CREATE DIRECTORY XMLDIR is 'PATH';   --- instead of 'PATH' you need to substitute the path you want to use

 

then grant access to this DIRECTORY

 

SQL>GRANT READ ON DIRECTORY XMLDIR to SCOTT:

 

The following PLSQL code should read the XML file and print the information out to your screen.

I have added enough comments that shall make the idea simple and therefore, extendible

 

declare

l_bfile BFILE;

l_clob CLOB;

l_parser dbms_xmlparser.Parser;

my_doc dbms_xmldom.DOMDocument-- this vairable shall hold XML parsed data

current_item_list dbms_xmldom.DOMNodeList;

current_item dbms_xmldom.DOMNode;

 

-- Declare local variable the correspond to the XML data

-- in more serious implementation , consider using RECORD type

 

master_id number;

master_name varchar2(100);

student_id number;

student_name varchar2(100);

BEGIN

 

-- Point to the XML file called college.xml which is located in the path pointed at by XMLDIR

l_bfile := BFileName('XMLDIR', 'college.xml');

dbms_lob.createtemporary(l_clob, cache=>FALSE);

 

-- Open the XML file in read mode

dbms_lob.open(l_bfile, dbms_lob.lob_readonly);

 

-- tranfer the file contents to CLOB variable

dbms_lob.loadFromFile(dest_lob => l_clob,

src_lob => l_bfile,

amount => dbms_lob.getLength(l_bfile));

dbms_lob.close(l_bfile);

-- This ends file manipulation and the file contents are  now in a CLOB vairable

 

-- This entry is important to deal with DATE format in the XML data

dbms_session.set_nls('NLS_DATE_FORMAT','''DD-MON-YYYY''');

 

-- Starting XML processing business

-- Create a parser.

l_parser := dbms_xmlparser.newParser;

-- Parse the document and create a new DOM document.

dbms_xmlparser.parseClob(l_parser, l_clob);

 

-- The xml parsed CLOB is not transfered to a variable called my_doc

 

my_doc := dbms_xmlparser.getDocument(l_parser);

-- Free resources associated with the CLOB and Parser now they are no longer needed.

dbms_lob.freetemporary(l_clob);

dbms_xmlparser.freeParser(l_parser);

 

-- The following statement shall search for a node starting with /college/master

-- Then it shall get the no of entries in this node. In our example the college/master contains only one

-- entry, but a big one, because it contains detail XML (there is ony one <master> </master>

 

current_item_list := dbms_xslprocessor.selectNodes(dbms_xmldom.makeNode(my_doc),'college/master');

-- note no slash at end

--dbms_output.put_line(dbms_xmldom.getLength(current_item_list)); -- find the no of entries in this node

 

FOR cur_ent IN 0 .. dbms_xmldom.getLength(current_item_list)-1 LOOP -- it should loop only once because the matser is one row

current_item := dbms_xmldom.item(current_item_list, cur_ent); --READ the current item from current entry

dbms_xslprocessor.valueOf(current_item,'id/text()',master_id); -- get the values from the XML Tag <ID>

dbms_xslprocessor.valueOf(current_item,'name/text()',master_name);

DBMS_OUTPUT.Put_Line( 'master value is : '|| master_id ||'-' ||master_name);

 

-- now identify the detail node so that you can loop over it and read its items like before

 

current_item_list := dbms_xslprocessor.selectNodes(dbms_xmldom.makeNode(my_doc),'/college/master/row');

 

-- note no slash at end

 

--dbms_output.put_line(dbms_xmldom.getLength(current_item_list));

    FOR cur_ent IN 0 .. dbms_xmldom.getLength(current_item_list)-1 LOOP

        current_item := dbms_xmldom.item(current_item_list, cur_ent);

                        dbms_xslprocessor.valueOf(current_item,'student_id/text()',student_id);

                        dbms_xslprocessor.valueOf(current_item,'student_name/text()',student_name);

                    DBMS_OUTPUT.Put_Line( '   <row> value is : '|| student_id ||'-' ||student_name );

     end loop;

end loop;

dbms_xmldom.freeDocument(My_doc);

end;

 

 

The output would be

 

master value is : 10-REALSOFT

  <row> value is : 1-Ahmad

  <row> value is : 2-Samia

  <row> value is : 3-Tareq