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 GetNodeName
function to read the element name but no SetNodeName
function 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;
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;