What's a good approach for concatenating the XMLType flavor
Using Oracle PLSQL, I came to a point where I created several XML fragments of type XMLType. I have them stored in VARRAY type XMLTYPE. I can successfully print them separately in a file.
Next, I want to combine all these pieces and wrap them in a different root element to create a single document. From what I've read, if I can get the XMLSEQUENCETYPE, I can just pass that to XMLCONCAT (..) and it should return the XMLType concatenation of all fragments. After that it will just be adding the root elements with XMLELEMENT (..). However, I am at a loss to find a way to generate the XMLSEQUENCETYPE from my VARRAY XMLTYPE.
Does anyone know how this can be done and is the approach I have taken really the best one? (If anyone is interested, I am trying to create a basic structure like dbunit. The purpose of this script is to create a tool that can be used to output XML DataSets to a file that is later loaded into unit tests).
Here's the plsql script:
set serveroutput on;
CREATE OR REPLACE TYPE rowset_query_type AS OBJECT (
table_name VARCHAR2(100),
query_string VARCHAR2(1024)
);
/
DECLARE
TYPE XML_Fragments_Type IS VARRAY(1000) OF XMLTYPE;
TYPE Rowset_Query_List_Type is VARRAY(1000) OF rowset_query_type;
outputDir VARCHAR(200) := 'ORACLE_FILE_DIR';
outputFile VARCHAR(200) := 'TestDataSet.xml';
qryCtx DBMS_XMLGEN.ctxHandle;
rowsetResultFragments XML_Fragments_Type;
rowsetQueries Rowset_Query_List_Type;
xmlResult xmltype;
rowsetQueryElement rowset_query_type;
output CLOB;
BEGIN
dbms_output.put_line('Exporting dataset...');
-- export files to data fixture
-- define fixtures
rowsetQueries := Rowset_Query_List_Type();
rowsetQueries.EXTEND(2);
rowsetQueries := Rowset_Query_List_Type(
rowset_query_type('person', 'select * from person'),
rowset_query_type('address','select * from address'));
rowsetResultFragments := XML_Fragments_Type();
rowsetResultFragments.EXTEND(rowsetQueries.count);
FOR i IN rowsetQueries.FIRST..rowsetQueries.LAST
LOOP
rowsetQueryElement := rowsetQueries(i);
dbms_output.put_line('Extracting dataset for table: ' || rowsetQueryElement.table_name || ' using query: ''' || rowsetQueryElement.query_string || '''');
qryCtx := dbms_xmlgen.newContext(rowsetQueryElement.query_string);
-- wrap the result up with a metadata tag containing the fixture tablename
select xmlelement(
"ROWSET_QUERY",
xmlattributes(rowsetQueryElement.table_name as "tableName"),
DBMS_XMLGEN.getXMLType(qryCtx)
)
into rowsetResultFragments(i)
from dual;
--close context
DBMS_XMLGEN.closeContext(qryCtx);
-- print the results to console
-- serialize the result for printing to output
SELECT XMLSERIALIZE(
CONTENT
rowsetResultFragments(i)
AS CLOB)
INTO output
FROM DUAL;
DBMS_OUTPUT.PUT_LINE(output);
END LOOP;
-- concatenate the set of rowsetQueries result fragments to a single result clob
-- ???
END;
/
source to share
you're almost there.
first change the type to SQL code:
create or replace TYPE XML_Fragments_Type IS VARRAY(1000) OF XMLTYPE;
/
then do it
-- concatenate the set of rowsetQueries result fragments to a single result clob
-- ???
select xmlelement("root" ,xmlagg(column_value))
into xmlresult
from table(rowsetResultFragments);
eg:
SQL> create or replace TYPE XML_Fragments_Type IS VARRAY(1000) OF XMLTYPE;
2 /
Type created.
SQL> DECLARE
2
3 --TYPE XML_Fragments_Type IS VARRAY(1000) OF XMLTYPE;
4 TYPE Rowset_Query_List_Type is VARRAY(1000) OF rowset_query_type;
5
6 outputDir VARCHAR(200) := 'ORACLE_FILE_DIR';
7 outputFile VARCHAR(200) := 'TestDataSet.xml';
8
...
26 rowsetQueries := Rowset_Query_List_Type(
27 rowset_query_type('person', 'select table_name, owner from dba_tables where rownum = 1'),
28 rowset_query_type('address','select owner, type_name, attributes from dba_types where rownum = 1'));
29
...
56
57 select xmlelement("root" ,xmlagg(column_value))
58 into xmlresult
59 from table(rowsetResultFragments);
60 SELECT XMLSERIALIZE(
61 CONTENT
62 xmlresult
63 AS CLOB )
64 INTO output
65 FROM DUAL;
66 DBMS_OUTPUT.PUT_LINE(output);
67
68
69 END;
70 /
Exporting dataset...
Extracting dataset for table: person using query: 'select table_name, owner from dba_tables where rownum = 1'
Extracting dataset for table: address using query: 'select owner, type_name, attributes from dba_types where rownum = 1'
<root>
<ROWSET_QUERY tableName="person">
<ROWSET>
<ROW>
<TABLE_NAME>ICOL$</TABLE_NAME>
<OWNER>SYS</OWNER>
</ROW>
</ROWSET>
</ROWSET_QUERY>
<ROWSET_QUERY tableName="address">
<ROWSET>
<ROW>
<OWNER>CTXSYS</OWNER>
<TYPE_NAME>CATINDEXMETHODS</TYPE_NAME>
<ATTRIBUTES>3</ATTRIBUTES>
</ROW>
</ROWSET>
</ROWSET_QUERY>
</root>
source to share
If you don't use these snippets, you can use XMLCONCAT in a loop, then XMLELEMENT at the end:
SQL> DECLARE
2 TYPE Rowset_Query_List_Type IS VARRAY(1000) OF rowset_query_type;
3
4 outputDir VARCHAR(200) := 'ORACLE_FILE_DIR';
5 outputFile VARCHAR(200) := 'TestDataSet.xml';
6
7 qryCtx DBMS_XMLGEN.ctxHandle;
8 rowsetQueries Rowset_Query_List_Type;
9 xmlResult XMLTYPE;
10 rowsetQueryElement rowset_query_type;
11 BEGIN
12 -- define fixtures
13 rowsetQueries := Rowset_Query_List_Type(
14 rowset_query_type('person', 'select * from dual'),
15 rowset_query_type('address', 'select * from dual'));
16
17 FOR i IN rowsetQueries.FIRST .. rowsetQueries.LAST LOOP
18
19 rowsetQueryElement := rowsetQueries(i);
20 dbms_output.put_line('Extracting dataset for table: '
21 || rowsetQueryElement.table_name
22 || ' using query: '''
23 || rowsetQueryElement.query_string || '''');
24
25 qryCtx := dbms_xmlgen.newContext(rowsetQueryElement.query_string);
26
27 -- concatenate
28 SELECT xmlconcat(xmlResult,
29 xmlelement(
30 "ROWSET_QUERY",
31 xmlattributes(
32 rowsetQueryElement.table_name AS "tableName"),
33 DBMS_XMLGEN.getXMLType(qryCtx)))
34 INTO xmlResult
35 FROM dual;
36
37 --close context
38 DBMS_XMLGEN.closeContext(qryCtx);
39
40 END LOOP;
41
42 -- root element
43 SELECT xmlelement(ROOT, xmlresult) INTO xmlresult FROM dual;
44
45 dbms_output.put_line('result:');
46 DBMS_OUTPUT.PUT_LINE(xmlResult.getClobVal());
47
48 END;
49 /
Extracting dataset for table: person using query: 'select * from dual'
Extracting dataset for table: address using query: 'select * from dual'
result:
<ROOT><ROWSET_QUERY tableName="person"><ROWSET>
<ROW>
<DUMMY>X</DUMMY>
</ROW>
</ROWSET>
</ROWSET_QUERY><ROWSET_QUERY tableName="address"><ROWSET>
<ROW>
<DUMMY>X</DUMMY>
</ROW>
</ROWSET>
</ROWSET_QUERY></ROOT>
PL/SQL procedure successfully completed
source to share