CREATE OR REPLACE PACKAGE create_xml IS
-- Declare XML types
type ry_path is record (
full_path varchar2(4000),
node_name varchar2(512),
node_path varchar2(4000),
attb_name varchar2(512),
attb_path varchar2(4000)
);
-- Constants
c_path_sep CONSTANT varchar2(1) := '/';
c_attb_sep CONSTANT varchar2(1) := '@';
c_function_sep_start CONSTANT varchar2(1) := '[';
c_function_sep_end CONSTANT varchar2(1) := ']';
-- Initialize XML
procedure init_xml(
p_domdoc in out dbms_xmldom.DOMDocument,
p_index_id in varchar2,
p_node_name in varchar2,
p_text_value in varchar2
);
-- Add and write node to XML DOMDocument
procedure create_node(
p_domdoc in out dbms_xmldom.DOMDocument,
p_index_id in varchar2,
p_node_name in varchar2,
p_text_value in varchar2
);
-- Add attribute to XML DOMDocument
procedure add_attr(
p_index_id in varchar2,
p_attr_name in varchar2,
p_text_value in varchar2
);
-- Add node or attribute to XML DOMDocument (path notation)
procedure add_element(
p_path in varchar2,
p_value in varchar2,
p_domdoc in out dbms_xmldom.DOMDocument
);
-- Tokenize Path expresion
function tokenize_path(
p_path in varchar2,
p_path_sep in varchar2 default c_path_sep,
p_attb_sep in varchar2 default c_attb_sep,
p_function_sep_start in varchar2 default c_function_sep_start,
p_function_sep_end in varchar2 default c_function_sep_end
) return ry_path;
-- Get parent in Path expresion
function get_parent(
p_path in varchar2
) return varchar2;
-- Write XML DOM to Blob
procedure write_xmldom2blob (
p_domdoc in dbms_xmldom.DOMDocument,
p_csid in number,
p_blob in out nocopy blob
);
-- Create an example
procedure xml_example;
END create_xml;
CREATE OR REPLACE PACKAGE BODY create_xml AS
-- Private types
-- Internal XML types
type ry_xmlelement is record (
p_parent dbms_xmldom.DOMNode,
p_element_name varchar2(512),
p_element dbms_xmldom.DOMElement,
p_node dbms_xmldom.DOMNode,
p_text_value varchar2(32767),
p_text dbms_xmldom.DOMText,
p_textnode dbms_xmldom.DOMNode
);
type ty_xmlelement is table of ry_xmlelement index by varchar2(32767);
-- Internal variables
tb_xmlelements ty_xmlelement;
-- Private functions and procedures
-- Add node to ty_xmlelement
procedure add_node(
p_index_id in varchar2,
p_node_name in varchar2,
p_text_value in varchar2
)
is
begin
-- Add node
tb_xmlelements(p_index_id).p_parent := tb_xmlelements(get_parent(p_index_id)).p_node;
tb_xmlelements(p_index_id).p_element_name := p_node_name;
tb_xmlelements(p_index_id).p_text_value := p_text_value;
end add_node;
-- Write node to XML DOMDocument
procedure write_node(
p_domdoc in out dbms_xmldom.DOMDocument,
p_index_id in varchar2
)
is
begin
-- Write node
tb_xmlelements(p_index_id).p_element := dbms_xmldom.createElement(p_domdoc, tb_xmlelements(p_index_id).p_element_name);
tb_xmlelements(p_index_id).p_node := dbms_xmldom.appendChild(tb_xmlelements(p_index_id).p_parent,dbms_xmldom.makeNode(tb_xmlelements(p_index_id).p_element));
tb_xmlelements(p_index_id).p_text := dbms_xmldom.createTextNode(p_domdoc, tb_xmlelements(p_index_id).p_text_value);
tb_xmlelements(p_index_id).p_textnode := dbms_xmldom.appendChild(tb_xmlelements(p_index_id).p_node,dbms_xmldom.makeNode(tb_xmlelements(p_index_id).p_text));
end write_node;
-- Public functions and procedures
-- Initialize XML
procedure init_xml(
p_domdoc in out dbms_xmldom.DOMDocument,
p_index_id in varchar2,
p_node_name in varchar2,
p_text_value in varchar2
)
is
l_root_node dbms_xmldom.DOMNode;
begin
-- Init internal table
tb_xmlelements.delete;
-- Create a root node
l_root_node := dbms_xmldom.makeNode(p_domdoc);
tb_xmlelements(p_index_id).p_parent := l_root_node;
tb_xmlelements(p_index_id).p_element_name := p_node_name;
tb_xmlelements(p_index_id).p_text_value := p_text_value;
write_node(p_domdoc, p_index_id);
end init_xml;
-- Add node to XML DOMDocument
procedure create_node(
p_domdoc in out dbms_xmldom.DOMDocument,
p_index_id in varchar2,
p_node_name in varchar2,
p_text_value in varchar2
)
is
begin
-- Add node
add_node(p_index_id, p_node_name, p_text_value);
-- Write node
write_node(p_domdoc, p_index_id);
end create_node;
-- Add attribute to XML DOMDocument
procedure add_attr(
p_index_id in varchar2,
p_attr_name in varchar2,
p_text_value in varchar2
)
is
begin
-- Add attribute
dbms_xmldom.setAttribute(
tb_xmlelements(p_index_id).p_element,
p_attr_name,
p_text_value);
end add_attr;
-- Add node or attribute to XML DOMDocument (path notation)
procedure add_element(
p_path in varchar2,
p_value in varchar2,
p_domdoc in out dbms_xmldom.DOMDocument
)
is
reg_path ry_path;
begin
-- Read p_path
reg_path := tokenize_path(p_path => p_path);
-- Switch node / attribute
if reg_path.attb_name is not null then
add_attr(
p_index_id => reg_path.attb_path,
p_attr_name => reg_path.attb_name,
p_text_value => p_value
);
else
create_node(
p_domdoc => p_domdoc,
p_index_id => reg_path.full_path,
p_node_name => reg_path.node_name,
p_text_value => p_value
);
end if;
end add_element;
-- Tokenize Path expresion
function tokenize_path(
p_path in varchar2,
p_path_sep in varchar2 default c_path_sep,
p_attb_sep in varchar2 default c_attb_sep,
p_function_sep_start in varchar2 default c_function_sep_start,
p_function_sep_end in varchar2 default c_function_sep_end
) return ry_path
is
v_path_sep varchar2(1);
v_attb_sep varchar2(1);
v_function_sep_start varchar2(1);
v_function_sep_end varchar2(1);
reg_path ry_path;
begin
-- Init variables
v_path_sep := nvl(p_path_sep, c_path_sep);
v_attb_sep := nvl(p_attb_sep, c_attb_sep);
v_function_sep_start := nvl(p_function_sep_start, c_function_sep_start);
v_function_sep_end := nvl(p_function_sep_end, c_function_sep_end);
reg_path.full_path := p_path;
-- Remove end path_sep
if substr(reg_path.full_path, -1, 1) = v_path_sep then
reg_path.full_path := substr(reg_path.full_path, 1, length(reg_path.full_path)-1);
end if;
-- Check for attrib
if instr(reg_path.full_path, v_path_sep||v_attb_sep, 1, 2) > 1 then
raise_application_error(-20001, 'Only one '||v_attb_sep||' is allowed.', true);
elsif instr(reg_path.full_path, v_path_sep||v_attb_sep) > 0 then
reg_path.attb_name := substr(reg_path.full_path, instr(reg_path.full_path, v_path_sep||v_attb_sep)+2);
reg_path.attb_path := substr(reg_path.full_path, 1, instr(reg_path.full_path, v_path_sep||v_attb_sep, -1)-1);
reg_path.node_path := substr(reg_path.full_path, 1, instr(reg_path.full_path, v_path_sep||v_attb_sep, -1)-1);
else
reg_path.node_path := reg_path.full_path;
end if;
-- Tokenize node
reg_path.node_name := regexp_substr(
regexp_substr(reg_path.node_path, '[^'||v_path_sep||']+$'),
'[^'||v_function_sep_start||'|'||v_path_sep||v_attb_sep||']+');
reg_path.node_path := substr(reg_path.node_path, 1, instr(reg_path.node_path, v_path_sep, -1)-1);
-- End
return reg_path;
end tokenize_path;
-- Get parent in Path expresion
function get_parent(
p_path in varchar2
) return varchar2
is
reg_path ry_path;
begin
-- Extract parent
reg_path := tokenize_path(p_path => p_path);
return reg_path.node_path;
end get_parent;
-- Write XML DOM to Blob
procedure write_xmldom2blob (
p_domdoc in dbms_xmldom.DOMDocument,
p_csid in number,
p_blob in out nocopy blob
)
is
cl_xml clob;
dest_offset integer := 1;
src_offset integer := 1;
lang_context integer := 0;
warning integer;
begin
-- Init variables
dbms_lob.createtemporary(lob_loc => cl_xml, cache => false, dur => dbms_lob.call);
-- Write XML DOM to Clob
dbms_xmldom.writeToClob(doc => p_domdoc, cl => cl_xml);
-- Convert Clob to Blob
dbms_lob.convertToBlob(
dest_lob => p_blob,
src_clob => cl_xml,
amount => dbms_lob.lobmaxsize,
dest_offset => dest_offset,
src_offset => src_offset,
blob_csid => p_csid,
lang_context => lang_context,
warning => warning);
-- Free resources
dbms_lob.freetemporary(lob_loc => cl_xml);
end write_xmldom2blob;
-- Create an example
procedure xml_example
IS
l_domdoc dbms_xmldom.DOMDocument;
v_buffer varchar2(32767);
begin
-- Create an empty XML document
l_domdoc := dbms_xmldom.newDomDocument;
-- Set version
dbms_xmldom.setVersion(l_domdoc, '1.0" encoding="ISO-8859-1');
--dbms_xmldom.setVersion(l_domdoc, '1.0');
--dbms_xmldom.setCharset(l_domdoc, 'ISO-8859-1');
-- Init XML
create_xml.init_xml(l_domdoc, '/root', 'root', null);
-- Add attributes to root node
create_xml.add_element('/root/@RootAttr01', 'Root Atribute 01', l_domdoc);
create_xml.add_element('/root/@RootAttr02', 'Root Atribute 02', l_domdoc);
-- Create a new node with text and attributes
create_xml.add_element('/root/node[1]', 'Node 01 text', l_domdoc);
create_xml.add_element('/root/node[1]/@Attr01', 'Atribute 01', l_domdoc);
create_xml.add_element('/root/node[1]/@Attr02', 'Atribute 02', l_domdoc);
-- Create a additional node with text
create_xml.add_element('/root/node[2]', '', l_domdoc);
-- Create a additional node paretn with child nodes
create_xml.add_element('/root/node_parent', '', l_domdoc);
create_xml.add_element('/root/node_parent/@AttrNew01', 'text attr new 01', l_domdoc);
create_xml.add_element('/root/node_parent/node_child[1]', 'Node Child aáa text 01', l_domdoc);
create_xml.add_element('/root/node_parent/node_child[2]', 'Node Child text 02', l_domdoc);
create_xml.add_element('/root/node_parent/node_child[3]', 'Node Child text 03', l_domdoc);
-- Add child to /root/node02
create_xml.add_element('/root/node[2]/node_child', 'Node 02 Child', l_domdoc);
-- Result
dbms_xmldom.writeToBuffer(l_domdoc, v_buffer, 'ISO-8859-1');
$if not dbms_db_version.ver_le_10_2 $then
select xmlserialize(DOCUMENT xmltype(v_buffer) AS varchar2(4000) INDENT) into v_buffer from dual;
$end
dbms_output.put_line(v_buffer);
dbms_xmldom.freeDocument(l_domdoc);
end xml_example;
END create_xml;
El paquete cuenta con un procedimiento de ejemplo:
begin
create_xml.xml_example;
end;
Resultado:
<?xml version="1.0" encoding="ISO-8859-1"?>
<root RootAttr01="Root Atribute 01" RootAttr02="Root Atribute 02">
<node Attr01="Atribute 01" Attr02="Atribute 02">Node 01 text</node>
<node>
<node>Node 02 Child</node>
</node>
<node AttrNew01="text attr new 01">
<node>Node Child aáa text 01</node>
<node Attr="Node Child 02 Attribute">Node Child text 02</node>
<node>Node Child text 03</node>
</node>
</root>
