Oracle har en indbygget funktion til at få indholdet af en tabel som 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>
Du kan tilføje dine egne tags omkring det; kunne gøres som en forespørgsel, men da du ønsker en lagret procedure:
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>
Så dette har den struktur, du ønsker (nå, tror jeg, men se nedenfor), men har ROWSET
og ROW
i stedet for RECORDS
og RECORD
. Det måske ligegyldigt, det afhænger af, om du stadig udvikler formatet til denne grænseflade. Hvis det betyder noget, kan du anvende et yderligere trin for at omdøbe disse noder
, eller - mere nyttigt - brug dbms_xmlgen
procedurer setrowsettag
og setrowtag
, hvilket er enkelt i din procedure (og demonstreret nedenfor).
Jeg går ud fra, hvad du viste som <TABLENAME></TABLENAME>
var en fejl, og du vil have posterne i det tag. Hvis ikke, og du virkelig ønsker det af en eller anden grund, skal du ændre forespørgslen i funktionen til:
select xmlelement("XML",
xmlconcat(xmlelement(evalname(table_name), null),
dbms_xmlgen.getxmltype('select * from "' || table_name || '"')))
into xml
from dual;
Du kan derefter skrive det ud til en fil, som du normalt ville; hvis du ringer fra SQL*Plus osv. kan du vælge og spoole, eller hvis du slet ikke vil have det returneret, kan du tilføje UTL_FILE
direktiv om at skrive filen fra proceduren, men det skal være til et biblioteksobjekt på DB-serveren, hvilket måske ikke er praktisk.
Mest til min egen fordel, da jeg ikke gør så meget med 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;
/
Når den køres med exec table_to_xml_file('T42')
, dette producerer en fil kaldet T42.xml
i serverbiblioteket, der peges på af <directory>
mappeobjekt, som indeholder:
<XML>
<T42>
<RECORDS>
<RECORD>
<ID>1</ID>
<STR>AA</STR>
</RECORD>
<RECORD>
<ID>2</ID>
<STR>BB</STR>
</RECORD>
</RECORDS>
</T42>
</XML>
Jeg har i øvrigt sat dobbelte anførselstegn omkring tabelnavnet i markeringen inde i dbms_xmlgen.getxmltype
opkald. Det er for at opfylde kravet om 'tilfældet skal være det samme som i databasen' for tabelnavnet; det skal videregives til proceduren i det rigtige tilfælde, ellers fejler det. Det er lettere end at prøve at rette sagen inden for proceduren på en eller anden måde, hvilket ville være besværligt eller umuligt, hvis du havde to borde med samme navn bortset fra sagen. Kolonnenavnene vil alligevel være med de rigtige bogstaver.