Oracle tiene una función integrada para obtener el contenido de una tabla 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>
Puede agregar sus propias etiquetas alrededor de eso; podría hacerse como una consulta, pero como desea un procedimiento almacenado:
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>
Esto tiene la estructura que desea (bueno, creo, pero vea a continuación), pero tiene ROWSET
y ROW
en lugar de RECORDS
y RECORD
. Eso podría no importa, depende de si aún está desarrollando el formato para esta interfaz. Si es importante, puede aplicar un paso adicional para cambiar el nombre de esos nodos
, o, más útil, use el dbms_xmlgen
procedimientos setrowsettag
y setrowtag
, que es simple en su procedimiento (y se demuestra a continuación).
Estoy asumiendo lo que mostraste como <TABLENAME></TABLENAME>
fue un error, y quiere los registros dentro de esa etiqueta. Si no es así, y realmente lo desea por alguna razón, cambie la consulta en la función a:
select xmlelement("XML",
xmlconcat(xmlelement(evalname(table_name), null),
dbms_xmlgen.getxmltype('select * from "' || table_name || '"')))
into xml
from dual;
Luego puede escribir eso en un archivo de la forma en que lo haría normalmente; si está llamando desde SQL * Plus, etc., puede seleccionar y poner en cola, o si no desea que se devuelva, puede agregar UTL_FILE
directiva para escribir el archivo desde dentro del procedimiento, pero eso tendría que ser en un objeto de directorio en el servidor DB, lo que podría no ser conveniente.
Principalmente para mi propio beneficio, ya que no hago mucho 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;
/
Cuando se ejecuta con exec table_to_xml_file('T42')
, esto produce un archivo llamado T42.xml
en el directorio del servidor al que apunta <directory>
objeto de directorio, que contiene:
<XML>
<T42>
<RECORDS>
<RECORD>
<ID>1</ID>
<STR>AA</STR>
</RECORD>
<RECORD>
<ID>2</ID>
<STR>BB</STR>
</RECORD>
</RECORDS>
</T42>
</XML>
Por cierto, puse comillas dobles alrededor del nombre de la tabla en la selección dentro de dbms_xmlgen.getxmltype
llamar. Eso es para cumplir con el requisito 'el caso debe ser el mismo que en la base de datos' para el nombre de la tabla; se tiene que pasar al procedimiento en el caso correcto o se producirá un error. Eso es más simple que tratar de corregir el caso dentro del procedimiento de alguna manera, lo que sería incómodo o imposible si tuviera dos tablas con el mismo nombre aparte del caso. Los nombres de las columnas estarán en el caso correcto de todos modos.