O Oracle possui uma função integrada para obter o conteúdo de uma tabela como 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>
Você pode adicionar suas próprias tags em torno disso; poderia ser feito como uma consulta, mas como você deseja um procedimento armazenado:
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>
Então isso tem a estrutura que você quer (bem, eu acho, mas veja abaixo), mas tem
ROWSET
e ROW
em vez de RECORDS
e RECORD
. Isso pode não importa, depende se você ainda está desenvolvendo o formato para essa interface. Se for importante, você pode aplicar mais uma etapa para renomear esses nós
, ou - mais útil - use o dbms_xmlgen
procedimentos setrowsettag
e setrowtag
, que é simples em seu procedimento (e demonstrado abaixo). Estou assumindo o que você mostrou como
<TABLENAME></TABLENAME>
foi um erro e você quer os registros dentro dessa tag. Se não, e você realmente quer isso por algum motivo, altere a consulta na função para: select xmlelement("XML",
xmlconcat(xmlelement(evalname(table_name), null),
dbms_xmlgen.getxmltype('select * from "' || table_name || '"')))
into xml
from dual;
Você pode então escrever isso em um arquivo da maneira que faria normalmente; se você estiver chamando do SQL*Plus etc., você pode selecionar e fazer o spool, ou se você não quiser que ele seja retornado, você pode adicionar
UTL_FILE
diretiva para gravar o arquivo de dentro do procedimento, mas isso teria que ser em um objeto de diretório no servidor de banco de dados, o que pode não ser conveniente. Principalmente para meu próprio benefício, pois não faço muito com 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 executado com
exec table_to_xml_file('T42')
, isso produz um arquivo chamado T42.xml
no diretório do servidor apontado pelo <directory>
objeto de diretório, que contém:<XML>
<T42>
<RECORDS>
<RECORD>
<ID>1</ID>
<STR>AA</STR>
</RECORD>
<RECORD>
<ID>2</ID>
<STR>BB</STR>
</RECORD>
</RECORDS>
</T42>
</XML>
Aliás, coloquei aspas duplas no nome da tabela no select dentro do
dbms_xmlgen.getxmltype
ligar. Isso é para atender ao requisito 'o caso deve ser o mesmo que no banco de dados' para o nome da tabela; ele tem que ser passado para o procedimento no caso correto ou dará erro. Isso é mais simples do que tentar corrigir o caso dentro do procedimento de alguma forma, o que seria estranho ou impossível se você tivesse duas tabelas com o mesmo nome além do caso. Os nomes das colunas estarão no caso correto de qualquer maneira.