DBMS_XMLDOM
The DBMS_XMLDOM package is used to access XMLType objects, and implements the Document Object Model (DOM), an application programming interface for HTML and XML documents. The Document Object Model (DOM) is an application programming interface (API) for HTML and XML documents. It defines the logical structure of documents, and the manner in which they are accessed and manipulated. To learn more about DBMS_XMLDOM package, please refer the documentation from Oracle.
We will be more specifically working with the following functions and procedures:
- newDomDocument
- makeNode
- appendChild
- createElement
- createTextNode
- getXmlType
- freeDocument
In this post, we will take a look at how to create XML using DBMS_XMLDOM package. We will be using the DBMS_XMLDOM package in a Oracle PL/SQL procedure to generate the XML file.
Generate Supplier Details
In our first example, we will look at how we can create supplier details in XML using PLSQL. The sample XML output is given below:
<SUPPLIER_DETAILS> <SUPPLIER> <SUPPLIER_NUMBER> </SUPPLIER_NUMBER> <SUPPLIER_NAME> </SUPPLIER_NAME> </SUPPLIER> <SUPPLIER> <SUPPLIER_NUMBER> </SUPPLIER_NUMBER> <SUPPLIER_NAME> </SUPPLIER_NAME> </SUPPLIER> </SUPPLIER_DETAILS>
Based on the above sample XML file, you can see that for each supplier the supplier name and number details are are repeated.
Now lets take a look at the PL/SQL code to generate the same xml file.
DECLARE l_xmltype XMLTYPE; l_domdoc dbms_xmldom.DOMDocument; l_root_node dbms_xmldom.DOMNode; l_supp_num_element dbms_xmldom.DOMElement; l_supp_name_element dbms_xmldom.DOMElement; l_supp_num_node dbms_xmldom.DOMNode; l_supp_name_node dbms_xmldom.DOMNode; l_supp_num_tnode dbms_xmldom.DOMNode; l_supp_name_tnode dbms_xmldom.DOMNode; l_supp_num_text dbms_xmldom.DOMText; l_supp_name_text dbms_xmldom.DOMText; l_supplier_element dbms_xmldom.DOMElement; l_supplier_node dbms_xmldom.DOMNode; l_sup_node dbms_xmldom.DOMNode; l_sup_element dbms_xmldom.DOMElement; BEGIN -- Create an empty XML document l_domdoc := dbms_xmldom.newDomDocument; -- Create a root node l_root_node := dbms_xmldom.makeNode(l_domdoc); -- Create a new Supplier Node and add it to the root node l_sup_node := dbms_xmldom.appendChild( l_root_node , dbms_xmldom.makeNode(dbms_xmldom.createElement(l_domdoc, 'SUPPLIER_ADDRESS')) ); FOR sup_rec IN (SELECT aps.vendor_name, aps.segment1, assa.address_line1, assa.city, assa.state, assa.zip FROM ap_suppliers aps, ap_supplier_sites_all assa WHERE assa.vendor_id = aps.vendor_id AND aps.vendor_id in (1003,1004) ORDER BY 2) LOOP -- For each record, create a new Supplier element -- and add this new Supplier element to the Supplier Parent node l_supplier_element := dbms_xmldom.createElement(l_domdoc, 'SUPPLIER' ); l_supplier_node := dbms_xmldom.appendChild(l_sup_node,dbms_xmldom.makeNode(l_supplier_element)); -- Each Supplier node will get a Number node which contains the Supplier Number as text l_supp_num_element := dbms_xmldom.createElement(l_domdoc, 'SUPPLIER_NUMBER' ); l_supp_num_node := dbms_xmldom.appendChild(l_supplier_node,dbms_xmldom.makeNode(l_supp_num_element)); l_supp_num_text := dbms_xmldom.createTextNode(l_domdoc, sup_rec.segment1 ); l_supp_num_tnode := dbms_xmldom.appendChild(l_supp_num_node,dbms_xmldom.makeNode(l_supp_num_text)); -- Each Supplier node will get a Name node which contains the Supplier Name as text l_supp_name_element := dbms_xmldom.createElement(l_domdoc, 'SUPPLIER_NAME' ); l_supp_name_node := dbms_xmldom.appendChild(l_supplier_node,dbms_xmldom.makeNode(l_supp_name_element)); l_supp_name_text := dbms_xmldom.createTextNode(l_domdoc, sup_rec.vendor_name ); l_supp_name_tnode := dbms_xmldom.appendChild(l_supp_name_node,dbms_xmldom.makeNode(l_supp_name_text)); END LOOP; l_xmltype := dbms_xmldom.getXmlType(l_domdoc); dbms_xmldom.freeDocument(l_domdoc); dbms_output.put_line(l_xmltype.getClobVal); END;
Generate Supplier and Address Details (Sub Group)
In the next example, we will look at how to generate the Address details as a sub group.
<SUPPLIER_ADDRESS> <SUPPLIER> <SUPPLIER_NUMBER> </SUPPLIER_NUMBER> <SUPPLIER_NAME> </SUPPLIER_NAME> <ADDRESS> <ADDRESS1> </ADDRESS1> <CITY> </CITY> <STATE> </STATE> <ZIP> </ZIP> </ADDRESS> </SUPPLIER> </SUPPLIER_ADDRESS>
As you can see, there is a new group / level (ADDRESS) within the “SUPPLIER” group. For each Address for a supplier, the “ADDRESS” group will be repeated as many times.
The below PLSQL package can be used to generate the same. You can see that I have used a cursor within in the first FOR Loop.
DECLARE l_xmltype XMLTYPE; l_domdoc dbms_xmldom.DOMDocument; l_root_node dbms_xmldom.DOMNode; l_supp_num_element dbms_xmldom.DOMElement; l_supp_name_element dbms_xmldom.DOMElement; l_address_element dbms_xmldom.DOMElement; l_city_element dbms_xmldom.DOMElement; l_state_element dbms_xmldom.DOMElement; l_zip_element dbms_xmldom.DOMElement; l_supp_num_node dbms_xmldom.DOMNode; l_supp_name_node dbms_xmldom.DOMNode; l_address_node dbms_xmldom.DOMNode; l_city_node dbms_xmldom.DOMNode; l_state_node dbms_xmldom.DOMNode; l_zip_node dbms_xmldom.DOMNode; l_supp_num_tnode dbms_xmldom.DOMNode; l_supp_name_tnode dbms_xmldom.DOMNode; l_address_tnode dbms_xmldom.DOMNode; l_city_tnode dbms_xmldom.DOMNode; l_state_tnode dbms_xmldom.DOMNode; l_zip_tnode dbms_xmldom.DOMNode; l_supp_num_text dbms_xmldom.DOMText; l_supp_name_text dbms_xmldom.DOMText; l_address_text dbms_xmldom.DOMText; l_city_text dbms_xmldom.DOMText; l_state_text dbms_xmldom.DOMText; l_zip_text dbms_xmldom.DOMText; l_supplier_element dbms_xmldom.DOMElement; l_supplier_node dbms_xmldom.DOMNode; l_sup_node dbms_xmldom.DOMNode; l_add_node dbms_xmldom.DOMNode; l_sup_element dbms_xmldom.DOMElement; l_add_element dbms_xmldom.DOMElement; BEGIN -- Create an empty XML document l_domdoc := dbms_xmldom.newDomDocument; -- Create a root node l_root_node := dbms_xmldom.makeNode(l_domdoc); -- Create a new Supplier Node and add it to the root node l_sup_node := dbms_xmldom.appendChild( l_root_node , dbms_xmldom.makeNode(dbms_xmldom.createElement(l_domdoc, 'SUPPLIER_INVOICES' )) ); FOR sup_rec IN (SELECT vendor_name, segment1, vendor_id FROM ap_suppliers WHERE vendor_id in (1003,1004)) LOOP -- For each record, create a new Supplier element -- and add this new Supplier element to the Supplier Parent node l_supplier_element := dbms_xmldom.createElement(l_domdoc, 'SUPPLIER' ); l_supplier_node := dbms_xmldom.appendChild(l_sup_node,dbms_xmldom.makeNode(l_supplier_element)); -- Each Supplier node will get a Number node which contains the Supplier Number as text l_supp_num_element := dbms_xmldom.createElement(l_domdoc, 'SUPPLIER_NUMBER' ); l_supp_num_node := dbms_xmldom.appendChild(l_supplier_node,dbms_xmldom.makeNode(l_supp_num_element)); l_supp_num_text := dbms_xmldom.createTextNode(l_domdoc, sup_rec.segment1 ); l_supp_num_tnode := dbms_xmldom.appendChild(l_supp_num_node,dbms_xmldom.makeNode(l_supp_num_text)); -- Each Supplier node will get a Name node which contains the Supplier Name as text l_supp_name_element := dbms_xmldom.createElement(l_domdoc, 'SUPPLIER_NAME' ); l_supp_name_node := dbms_xmldom.appendChild(l_supplier_node,dbms_xmldom.makeNode(l_supp_name_element)); l_supp_name_text := dbms_xmldom.createTextNode(l_domdoc, sup_rec.vendor_name ); l_supp_name_tnode := dbms_xmldom.appendChild(l_supp_name_node,dbms_xmldom.makeNode(l_supp_name_text)); FOR add_rec IN (SELECT address_line1, city, state, zip FROM ap_supplier_sites_all WHERE vendor_id = sup_rec.vendor_id) LOOP l_add_element := dbms_xmldom.createElement(l_domdoc, 'ADDRESS' ); l_add_node := dbms_xmldom.appendChild(l_supplier_node,dbms_xmldom.makeNode(l_add_element)); -- Each Address node will get a Address node which contains the Supplier Address Line1 as text l_address_element := dbms_xmldom.createElement(l_domdoc, 'ADDRESSS1' ); l_address_node := dbms_xmldom.appendChild(l_add_node,dbms_xmldom.makeNode(l_address_element)); l_address_text := dbms_xmldom.createTextNode(l_domdoc, add_rec.address_line1 ); l_address_tnode := dbms_xmldom.appendChild(l_address_node,dbms_xmldom.makeNode(l_address_text)); -- Each Address node will get a City node which contains the City as text l_city_element := dbms_xmldom.createElement(l_domdoc, 'CITY' ); l_city_node := dbms_xmldom.appendChild(l_add_node,dbms_xmldom.makeNode(l_city_element)); l_city_text := dbms_xmldom.createTextNode(l_domdoc, add_rec.city ); l_city_tnode := dbms_xmldom.appendChild(l_city_node,dbms_xmldom.makeNode(l_city_text)); -- Each Address node will get a State node which contains the State as text l_state_element := dbms_xmldom.createElement(l_domdoc, 'STATE' ); l_state_node := dbms_xmldom.appendChild(l_add_node,dbms_xmldom.makeNode(l_state_element)); l_state_text := dbms_xmldom.createTextNode(l_domdoc, add_rec.state ); l_state_tnode := dbms_xmldom.appendChild(l_state_node,dbms_xmldom.makeNode(l_state_text)); -- Each Address node will get a Zip node which contains the Zip Code as text l_zip_element := dbms_xmldom.createElement(l_domdoc, 'ZIP' ); l_zip_node := dbms_xmldom.appendChild(l_add_node,dbms_xmldom.makeNode(l_zip_element)); l_zip_text := dbms_xmldom.createTextNode(l_domdoc, add_rec.zip ); l_zip_tnode := dbms_xmldom.appendChild(l_zip_node,dbms_xmldom.makeNode(l_zip_text)); END LOOP; END LOOP; l_xmltype := dbms_xmldom.getXmlType(l_domdoc); dbms_xmldom.freeDocument(l_domdoc); dbms_output.put_line(l_xmltype.getClobVal); END;
You can use the same concepts to create XML using DBMS_XMLDOM package. You can have nested groups or n-number of sub groups etc in the XML Document.
Leave your comments and feedback and also post any questions that you may have.
Questions? Comments? Suggestions? Let us know!! Like / Subscribe / Follow for more updates.