Search code examples
xmloracleplsql

Creating tags (or nodes) with a Namespace PL/SQL


The following PL/SQL block...

DECLARE
   doc_   dbms_XmlDom.DomDocument := Dbms_XmlDom.newDomDocument;
   nd_    dbms_XmlDom.DomNode;
   nd2_   dbms_XmlDom.DomNode;
   tag_   dbms_XmlDom.DomElement;
   out_   VARCHAR2(32000);
   ns_    VARCHAR2(20) := 'cp';
BEGIN
   Dbms_XmlDom.setVersion (doc_, '1.0" encoding="UTF-8" standalone="yes');
   tag_ := Dbms_XmlDom.createElement (
      doc     => doc_,
      tagName => 'coreProperties',
      ns      => ns_
   );
   nd2_ := Dbms_XmlDom.makeNode (tag_);
   nd_  := Dbms_XmlDom.appendChild (Dbms_XmlDom.makeNode(doc_), nd2_);

   out_ := Dbms_XmlDom.getXmlType(doc_).getClobVal;
   Dbms_XmlDom.freeDocument (doc_);
   Dbms_Output.Put_Line (out_);
END;

... produces this XML output:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<coreProperties/>

I would expect it to create this output instead (i.e. with the tag-name being namespaced)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties/>

I know I can change the createElement() call to generate the desired output

--- blah...
   tag_ := Dbms_XmlDom.createElement (
      doc     => doc_,
      tagName => ns_ || ':coreProperties'
   );
--- blah

... but that seems silly when there's a documented ns parameter that's expecting data to be passed into it. (It also becomes a little verbose and messy in a real-world setting).

What am I missing here? What am I doing wrong?

(Tested in Oracle Free 23ai, but should be backwardly compatible to Oracle 11)


Solution

  • You can add a prefix to your node with the setPrefix procedure - in your example this works against either nd_ or nd2_:

    Dbms_XmlDom.setPrefix (nd_, ns_);
    

    And you can declare the namespace with setAttribute, which you may already know:

    Dbms_XmlDom.setAttribute(tag_, 'xmlns:cp', 'http://example.com');
    

    Adding those to your code gives you:

    DECLARE
       doc_   dbms_XmlDom.DomDocument := Dbms_XmlDom.newDomDocument;
       nd_    dbms_XmlDom.DomNode;
       nd2_   dbms_XmlDom.DomNode;
       tag_   dbms_XmlDom.DomElement;
       out_   VARCHAR2(32000);
       ns_    VARCHAR2(20) := 'cp';
    BEGIN
       Dbms_XmlDom.setVersion (doc_, '1.0" encoding="UTF-8" standalone="yes');
       tag_ := Dbms_XmlDom.createElement (
          doc     => doc_,
          tagName => 'coreProperties',
          ns      => ns_
       );
       Dbms_XmlDom.setAttribute(tag_, 'xmlns:cp', 'http://example.com');
       nd2_ := Dbms_XmlDom.makeNode (tag_);
       nd_  := Dbms_XmlDom.appendChild (Dbms_XmlDom.makeNode(doc_), nd2_);
       Dbms_XmlDom.setPrefix (nd_, ns_);
    
       out_ := Dbms_XmlDom.getXmlType(doc_).getClobVal;
       Dbms_XmlDom.freeDocument (doc_);
       Dbms_Output.Put_Line (out_);
    END;
    /
    
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <cp:coreProperties xmlns:cp="http://example.com"/>
    

    fiddle (as 21c, also works the same in 23ai and 11gR2)