Oracle a une fonction intégrée pour obtenir le contenu d'une table au format 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>
Vous pouvez ajouter vos propres balises autour de cela; pourrait être fait comme une requête mais puisque vous voulez une procédure stockée :
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>
Donc, cela a la structure que vous voulez (enfin, je pense, mais voir ci-dessous), mais a ROWSET
et ROW
au lieu de RECORDS
et RECORD
. Cela pourrait peu importe, cela dépend si vous développez encore le format de cette interface. Si cela importe, vous pouvez appliquer une étape supplémentaire pour renommer ces nœuds
, ou - plus utilement - utilisez le dbms_xmlgen
procédures setrowsettag
et setrowtag
, ce qui est simple dans votre procédure (et illustré ci-dessous).
Je suppose ce que vous avez montré comme <TABLENAME></TABLENAME>
était une erreur, et vous voulez les enregistrements dans cette balise. Si ce n'est pas le cas, et que vous le souhaitez vraiment pour une raison quelconque, modifiez la requête dans la fonction :
select xmlelement("XML",
xmlconcat(xmlelement(evalname(table_name), null),
dbms_xmlgen.getxmltype('select * from "' || table_name || '"')))
into xml
from dual;
Vous pouvez ensuite l'écrire dans un fichier comme vous le feriez normalement; si vous appelez depuis SQL*Plus, etc., vous pouvez sélectionner et mettre en file d'attente, ou si vous ne voulez pas qu'il soit renvoyé du tout, vous pouvez ajouter UTL_FILE
directive pour écrire le fichier à partir de la procédure, mais cela devrait être dans un objet de répertoire sur le serveur de base de données, ce qui pourrait ne pas être pratique.
Surtout pour mon propre bénéfice car je ne fais pas beaucoup avec 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;
/
Lorsqu'il est exécuté avec exec table_to_xml_file('T42')
, cela produit un fichier appelé T42.xml
dans le répertoire du serveur pointé par le <directory>
objet répertoire, qui contient :
<XML>
<T42>
<RECORDS>
<RECORD>
<ID>1</ID>
<STR>AA</STR>
</RECORD>
<RECORD>
<ID>2</ID>
<STR>BB</STR>
</RECORD>
</RECORDS>
</T42>
</XML>
Incidemment, j'ai mis des guillemets autour du nom de la table dans la sélection à l'intérieur du dbms_xmlgen.getxmltype
appel. C'est pour répondre à l'exigence "la casse doit être la même que dans la base de données" pour le nom de la table ; il doit être passé à la procédure dans le bon cas ou il y aura une erreur. C'est plus simple que d'essayer de corriger la casse dans la procédure d'une manière ou d'une autre, ce qui serait gênant, voire impossible si vous aviez deux tables portant le même nom en dehors de la casse. Les noms de colonnes seront de toute façon dans la bonne casse.