Oracle ha una funzione integrata per ottenere il contenuto di una tabella come XML:
create table t42(id number, str varchar2(10));
insert into t42 values (1, 'AA');
insert into t42 values (2, 'BB');
select dbms_xmlgen.getxmltype('select * from t42')
from dual;
DBMS_XMLGEN.GETXMLTYPE('SELECT*FROMT42')
----------------------------------------
<ROWSET>
<ROW>
<ID>1</ID>
<STR>AA</STR>
</ROW>
<ROW>
<ID>2</ID>
<STR>BB</STR>
</ROW>
</ROWSET>
Puoi aggiungere i tuoi tag intorno a questo; potrebbe essere eseguita come una query ma poiché si desidera una procedura memorizzata:
create or replace function table_to_xml(table_name in varchar2) return xmltype as
xml xmltype;
begin
select xmlelement("XML",
xmlelement(evalname(table_name),
dbms_xmlgen.getxmltype('select * from "' || table_name || '"')))
into xml
from dual;
return xml;
end table_to_xml;
/
select table_to_xml('T42') from dual;
TABLE_TO_XML('T42')
----------------------------------------
<XML><T42><ROWSET>
<ROW>
<ID>1</ID>
<STR>AA</STR>
</ROW>
<ROW>
<ID>2</ID>
<STR>BB</STR>
</ROW>
</ROWSET>
</T42></XML>
Quindi questo ha la struttura che desideri (beh, penso, ma vedi sotto), ma ha ROWSET
e ROW
invece di RECORDS
e RECORD
. Questo potrebbe non importa, dipende se stai ancora sviluppando il formato per questa interfaccia. Se è importante, puoi applicare un ulteriore passaggio per rinominare quei nodi
o, in modo più utile, utilizzare dbms_xmlgen
procedure setrowsettag
e setrowtag
, che è semplice nella tua procedura (e illustrato di seguito).
Presumo quello che hai mostrato come <TABLENAME></TABLENAME>
è stato un errore e vuoi i record all'interno di quel tag. In caso contrario, e lo vuoi davvero per qualche motivo, cambia la query nella funzione in:
select xmlelement("XML",
xmlconcat(xmlelement(evalname(table_name), null),
dbms_xmlgen.getxmltype('select * from "' || table_name || '"')))
into xml
from dual;
Puoi quindi scriverlo in un file come faresti normalmente; se stai chiamando da SQL*Plus ecc. puoi selezionare e fare lo spool, oppure se non vuoi che venga restituito puoi aggiungere UTL_FILE
direttiva per scrivere il file dall'interno della procedura, ma dovrebbe essere in un oggetto directory sul server DB, il che potrebbe non essere conveniente.
Principalmente a mio vantaggio poiché non faccio molto con XML:
create or replace procedure table_to_xml_file(table_name in varchar2) as
ctx dbms_xmlgen.ctxhandle;
clb clob;
file utl_file.file_type;
buffer varchar2(32767);
position pls_integer := 1;
chars pls_integer := 32767;
begin
ctx := dbms_xmlgen.newcontext('select * from "' || table_name || '"');
dbms_xmlgen.setrowsettag(ctx, 'RECORDS');
dbms_xmlgen.setrowtag(ctx, 'RECORD');
select xmlserialize(document
xmlelement("XML",
xmlelement(evalname(table_name),
dbms_xmlgen.getxmltype(ctx)))
indent size = 2)
into clb
from dual;
dbms_xmlgen.closecontext(ctx);
file := utl_file.fopen('<directory>', table_name || '.xml', 'w', 32767);
while position < dbms_lob.getlength(clb) loop
dbms_lob.read(clb, chars, position, buffer);
utl_file.put(file, buffer);
utl_file.fflush(file);
position := position + chars;
end loop;
utl_file.fclose(file);
end table_to_xml_file;
/
Quando eseguito con exec table_to_xml_file('T42')
, questo produce un file chiamato T42.xml
nella directory del server indicata da <directory>
oggetto directory, che contiene:
<XML>
<T42>
<RECORDS>
<RECORD>
<ID>1</ID>
<STR>AA</STR>
</RECORD>
<RECORD>
<ID>2</ID>
<STR>BB</STR>
</RECORD>
</RECORDS>
</T42>
</XML>
Per inciso, ho inserito tra virgolette intorno al nome della tabella nella selezione all'interno di dbms_xmlgen.getxmltype
chiamata. Questo per soddisfare il requisito "case dovrebbe essere lo stesso del database" per il nome della tabella; deve essere passato alla procedura nel caso corretto o si verificherà un errore. È più semplice che cercare di correggere il caso all'interno della procedura in qualche modo, il che sarebbe imbarazzante o impossibile se avessi due tabelle con lo stesso nome a parte il caso. I nomi delle colonne saranno comunque nel caso corretto.