Skip to Main Content
  • Questions
  • How to copy a DBMS_XMLDOM.domnode between DBMS_XMLDOM.domdocument objects

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Kevin.

Asked: September 22, 2016 - 2:45 pm UTC

Last updated: April 16, 2019 - 11:49 pm UTC

Version: 11.2

Viewed 10K+ times! This question is

You Asked

I'm having trouble using the DBMS_XMLDOM package. I can hardly find more online than the API (which isn't that great) and a few "here's how you build an XML document" introductions, with no tutorials on more advanced uses. I am trying to write a file parser / converter that uses a Context Free Grammar to tokenize a data file and convert it to XML as a way to quickly support new file formats with minimal need to write new code. My implementation involves a few procedures that call each other, with the likelihood of recursion. At each level, some XML is generated and returned to the calling procedure. Problem being, I have a DBMS_XMLDOM.domdocument object local to each procedure which I use for the output. When output from one procedure is returned to the calling procedure, I need to copy content from the returned XML document into the local XML document. DBMS_XMLDOM won't let me just append the node onto the destination document like this (nodes must have the same parent document) - the prescribed workaround seems to be to:
1 - clone the node of interest from the source document
2 - import the node into the destination document
3 - append the node in the desired position within the destination document

Sample Code:
https://livesql.oracle.com/apex/livesql/s/dwifcd7f9qfewurk4exy2f9vq

The problem is that when I append the desired node into the destination document, the destination document does not appear to update. What am I missing?

and Connor said...

Do you need to initialize the dest document ?

SQL> set serverout on
SQL> DECLARE
  2      src_doc DBMS_XMLDOM.domdocument;
  3      src_root DBMS_XMLDOM.domnode;
  4      src_elem DBMS_XMLDOM.domelement;
  5      src_node DBMS_XMLDOM.domnode;
  6      src_clone DBMS_XMLDOM.domnode;
  7      dest_doc DBMS_XMLDOM.domdocument;
  8      dest_root DBMS_XMLDOM.domnode;
  9      buff varchar2(100);
 10  BEGIN
 11      --- create source document
 12      src_doc := DBMS_XMLDOM.newdomdocument;
 13      src_root := DBMS_XMLDOM.makenode(doc => src_doc);
 14
 15      --- create content in source document
 16      src_elem := DBMS_XMLDOM.createElement(doc => src_doc, tagName => 'Foo');
 17      src_node := DBMS_XMLDOM.makenode(elem => src_elem);
 18      src_node := DBMS_XMLDOM.appendChild(n => src_root, newChild => src_node);
 19
 20      --- prove that the node has content
 21      DBMS_XMLDOM.writetobuffer(n => src_node, buffer => buff);
 22      DBMS_OUTPUT.PUT_LINE('Original: {' || buff || '}');
 23
 24      --- clone node from source document
 25      src_clone := DBMS_XMLDOM.clonenode(n => src_node, deep => true);
 26
 27      --- prove that the clone has content
 28      DBMS_XMLDOM.writetobuffer(n => src_clone, buffer => buff);
 29      DBMS_OUTPUT.PUT_LINE('Clone: {' || buff || '}');
 30
 31  --
 32  -- init the dest
 33  --
 34      dest_doc := DBMS_XMLDOM.newdomdocument;
 35      dest_root := DBMS_XMLDOM.makenode(doc => dest_doc);
 36
 37      --- add clone to destination document
 38      src_clone := DBMS_XMLDOM.importnode(doc => dest_doc, importednode => src_clone, deep => true);
 39      src_clone := DBMS_XMLDOM.appendChild(n => dest_root, newChild => src_clone);
 40
 41      --- expect content to be in the destination document
 42      DBMS_XMLDOM.writetobuffer(n => dest_root, buffer => buff);
 43      DBMS_OUTPUT.PUT_LINE('Dest: {' || buff || '}');
 44  END;
 45  /
Original: {<Foo/>
}
Clone: {<Foo/>
}
Dest: {<Foo/>
}

PL/SQL procedure successfully completed.


Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Correction

Kevin Daines, September 27, 2016 - 8:31 pm UTC

I figured it out. Initializing the destination was not the solution I used. What's important to note is that a DBMS_XMLDOM.domnode can actually be any one of several DOM node types (revealed by DBMS_XMLDOM.getnodetype). If the node is the root node of a DBMS_XMLDOM.domdocument object, then it is considered to be a "document" node, verses an "element" node or a "notation" node (among others) if it appears lower in the document tree. Depending on the node type, you can do different things to the node. For example, you cannot add a "document" node as a child to another kind of node, which is what I was effectively trying to do. The solution was to cast the "document" node to an "element" node before cloning, as in:
src_clone := DBMS_XMLDOM.clonenode(n => DBMS_XMLDOM.makenode(DBMS_XMLDOM.getdocumentelement(src_doc)), deep => true);

Connor McDonald
September 28, 2016 - 7:35 am UTC

Nice work, and thanks for taking the time to give us an update.

Then everyone benefits.

Terrific...this really helped me!!!

Francesco Antolini, April 16, 2019 - 1:07 pm UTC

Ok, my problem was that trying to import an XMLType into a DOMDocument using dbms_xmldom.importnode(), it failed.
Using dbms_xmldom.getdocumentelement(), it worked!

1. BEFORE (didn't work)
DECLARE
...
xmlTypeElement SYS.XMLTYPE;
l_xmlDoc dbms_xmldom.domdocument;
l_testDoc dbms_xmldom.domdocument;
l_wrkNode dbms_xmldom.domnode;
l_testNode dbms_xmldom.domnode;
BEGIN
...
l_testDoc := dbms_xmldom.newDOMDocument(xmlTypeElement);
l_wrkNode := dbms_xmldom.makenode(l_testDoc);
...
l_testNode := dbms_xmldom.importnode(l_xmlDoc, l_wrkNode, TRUE);
END;

2. AFTER (IT WORKED!)
DECLARE
...
xmlTypeElement SYS.XMLTYPE;
l_xmlDoc dbms_xmldom.domdocument;
l_testDoc dbms_xmldom.domdocument;
l_wrkNode dbms_xmldom.domnode;
l_testNode dbms_xmldom.domnode;
BEGIN
...
l_testDoc := dbms_xmldom.newDOMDocument(xmlTypeElement);
l_wrkNode := dbms_xmldom.makenode(DBMS_XMLDOM.getdocumentelement(l_testDoc));
...
l_testNode := dbms_xmldom.importnode(l_xmlDoc, l_wrkNode, TRUE);
END;


Connor McDonald
April 16, 2019 - 11:49 pm UTC

Glad we could assist.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library