Search code examples
databaseoracle-databasexmldom

How can I change the name of an XML element in Oracle DBMS_XMLDOM?


When writing a function that composes some existing XMLTYPE data into another XML document I need to rename the document element of the inserted data. Looking at the DBMS_XMLDOM documentation it seems there is only a GetNodeNamefunction to read the element name but no SetNodeNamefunction to change an element name.

How can I change the name of an XML element when working with DBMS_XMLDOM? Or is this only possible with falling back to XSL transformation?

Minimized PL/SQL example:

DECLARE
  v_ResultDoc XmlDom.DomDocument;
  v_ResultXml XMLTYPE;
  v_ResultNode XmlDom.DomNode;
  v_ClientDoc XmlDom.DomDocument;
  v_ClientXml XMLTYPE;
  v_Node XmlDom.DomNode;  
BEGIN
  v_ResultDoc := XmlDom.NewDomDocument('<Result/>');
  v_ResultNode := XmlDom.MakeNode(XmlDom.GetDocumentElement(v_ResultDoc));

  v_ClientXml := XMLTYPE('<Foo>Some data generated by another function</Foo>');
  v_ClientDoc := XmlDom.NewDomDocument(v_ClientXml);
  v_Node := XmlDom.MakeNode(XmlDom.GetDocumentElement(v_ClientDoc));
  v_Node := XmlDom.AppendChild(v_ResultNode, XmlDom.AdoptNode(v_ResultDoc, v_Node));
  XmlDom.FreeDocument(v_ClientDoc);

  -- TODO: modify XML to <Result><Bar>Some data generated by another function</Bar></Result>
  v_ResultXml := XmlDom.GetXmlType(v_ResultDoc);
  XmlDom.FreeDocument(v_ResultDoc);
END;

Solution

  • It seems there is no DBMS_XMLDOM function to rename an element name and the only option (without falling back to XSL) is to generate a new parent element, iterate through all child nodes, and move them to the new parent node:

    DECLARE
      v_ResultDoc XmlDom.DomDocument;
      v_ResultXml XMLTYPE;
      v_ResultNode XmlDom.DomNode;
      v_ClientDoc XmlDom.DomDocument;
      v_ClientXml XMLTYPE;
      v_ClientNode XmlDom.DomNode;
      v_NodeList XmlDom.DomNodeList;
      v_Node XmlDom.DomNode;  
      i INT;
    BEGIN
      v_ResultDoc := XmlDom.NewDomDocument('<Result/>');
      v_ResultNode := XmlDom.MakeNode(XmlDom.GetDocumentElement(v_ResultDoc));
    
      v_ClientXml := XMLTYPE('<Foo>Some data generated by another function</Foo>');
      v_ClientDoc := XmlDom.NewDomDocument(v_ClientXml);
      v_ClientNode := XmlDom.AppendChild(v_ResultNode,
        XmlDom.MakeNode(XmlDom.CreateElement(v_ResultDoc, 'Bar')));
      v_Node := XmlDom.MakeNode(XmlDom.GetDocumentElement(v_ClientDoc));
      v_NodeList := XmlDom.GetChildNodes(v_Node);
      FOR i IN 0..XmlDom.GetLength(v_NodeList)-1 LOOP
        v_Node := XmlDom.Item(v_NodeList, i);
        v_Node := XmlDom.AppendChild(v_ClientNode,
          XmlDom.AdoptNode(v_ResultDoc, v_Node));
      END LOOP;
      XmlDom.FreeDocument(v_ClientDoc);
    
      v_ResultXml := XmlDom.GetXmlType(v_ResultDoc);
      XmlDom.FreeDocument(v_ResultDoc);
    
      -- do something with v_ResultXml ...
    END;