xmloracle-databaseplsqlora-06512

error reading xml from the plsql procedure


I am trying to read a xml from plsql procedure using the xmlparser package, i am getting this error

ORA-31020: The operation is not allowed, Reason: Not supported
ORA-06512: at "XDB.DBMS_XMLPARSER", line 395
ORA-06512: at "SYS.DOMSAMPLE", line 75
ORA-06512: at line 2

DOMSAMPLE is my procedure name, and no statements are there at line number 75, and next line contains p := xmlparser.newParser.

Can somebody please help me in resolving this problem. Or suggest a simple way to read xml in plsql.


Solution

  • You have provided scant few details about what you are actually doing, so I'm afraid I can only guess.

    I cannot reproduce the error message you have, but I have only tried a few things. Perhaps you're calling the Oracle XML APIs incorrectly? Perhaps there's something odd about the XML document you're attempting to parse? I'm afraid I have no idea, since you haven't given us the source of your DOMSAMPLE procedure nor the XML document you're attempting to parse.

    I cannot believe line 75 of your procedure is a blank line. Is this line 75 of the procedure, or line 75 of the file that contains the procedure?

    Here's an example using DBMS_XMLPARSER and DBMS_XMLDOM. It merely reads out the name of the root element of the XML string given:

    SET SERVEROUTPUT ON;
    
    DECLARE
       p    dbms_xmlparser.parser;
       d    dbms_xmldom.domdocument;
       e    dbms_xmldom.domelement;
    BEGIN
       p := dbms_xmlparser.newParser;
       dbms_xmlparser.parseBuffer(p, '<thisIsATest />');
       d := dbms_xmlparser.getDocument(p);
       e := dbms_xmldom.getDocumentElement(d);
       dbms_output.put_line('Tag name is ' || dbms_xmldom.getTagName(e));
    END;
    /
    

    When I run this it gives me the output Tag name is thisIsATest.

    As for simpler ways to read XML, there's one in a question I answered earlier. I don't know whether that will help you, because I know very little about what you're trying to achieve.

    Finally, please don't create objects in the SYS schema.

    EDIT: in your comment, you mention that you're using dbms_xmlparser.parse instead of dbms_xmlparser.parseBuffer. I had a play with dbms_xmlparser.parse and hit the same 'invalid resource handle or path name' error several times before finally finding something that worked. Below is what I managed to get working; there may well be a better solution to what you want than this.

    Before you can do any file I/O with Oracle, and that appears to include using dbms_xmlparser.parse, you must first create an Oracle 'directory'. Directories in Oracle correspond to directories on the filesystem. Note that this is the filesystem on the machine on which the Oracle database runs. If the XML file isn't on the same filesystem (e.g. the Oracle database is on a server and your XML file is on your development PC), you won't be able to use dbms_xmlparser.parse, unless you first transfer this file to a directory on the database server's filesystem.

    I'll start by creating a Oracle directory corresponding to a directory on my filesystem:

    SQL> create or replace directory ora_dir as '/home/luke/ora_dir';
    
    Directory created.
    

    I'm using Linux here. If you're using Windows, feel free to reverse the direction of the slashes.

    Before we go any further, let's take a quick look at the XML file we'll read in:

    SQL> host cat /home/luke/ora_dir/example.xml
    <?xml version="1.0" ?>
    <root>
      <child />
    </root>
    

    In SQL*Plus, host sends the rest of the line to the shell, or cmd.exe on Windows. On Windows you'd also use type instead of cat.

    Finally, here's a PL/SQL block that reads this XML file:

    SQL> set serveroutput on
    SQL> DECLARE
      2     p    dbms_xmlparser.parser;
      3     d    dbms_xmldom.domdocument;
      4     e    dbms_xmldom.domelement;
      5  BEGIN
      6     p := dbms_xmlparser.newParser;
      7     dbms_xmlparser.setBaseDir(p, 'ORA_DIR');
      8     dbms_xmlparser.parse(p, 'example.xml');
      9     d := dbms_xmlparser.getDocument(p);
     10     e := dbms_xmldom.getDocumentElement(d);
     11     dbms_output.put_line('Tag name is ' || dbms_xmldom.getTagName(e));
     12  END;
     13  /
    Tag name is root
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    The only difference between this block and the one further up is that the line that called dbms_xmlparser.parseBuffer has been replaced with two lines. The first of these two lines calls dbms_xmlparser.setBaseDir to set a base directory for the parser, and the second calls dbms_xmlparser.parse using a filename relative to this directory.

    EDIT 2: Your code, which wasn't working quite as you had hoped, and which you edited into my answer, is as follows:

    create or replace procedure printElements(doc xmldom.DOMDocument) is
    nl xmldom.DOMNodeList;
    len number;
    n xmldom.DOMNode;
    e xmldom.DOMElement;
    nodeval varchar2(100);
    begin
       -- get all elements
       nl := xmldom.getElementsByTagName(doc, '*');
       len := xmldom.getLength(nl);   
       -- loop through elements
       for i in 0..len-1 loop
          n := xmldom.item(nl, i);
          e := xmldom.makeElement(n => n);
          dbms_output.put(xmldom.getNodeName(n) || ' ');
          nodeval := xmldom.getNodeValue(n);
          -- here nodeval i am getting as null, what mistake am doing?
          dbms_output.put_line('  Value: '|| nodeval );
    
       end loop;
    
       dbms_output.put_line('');
    end printElements;
    

    This apparently was returning all the values as null, as suggested by the last of the three comments.

    To quote a previous answer of mine on a similar question:

    In XML DOM, elements don't have any 'value' to speak of. Element nodes contain Text nodes as children, and it is these nodes that contain the values you want.

    So, try replacing the line

          nodeval := xmldom.getNodeValue(n);
    

    with

          nodeval := xmldom.getNodeValue(xmldom.getFirstChild(n));