Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Generieren Sie XML aus Oracle-Tabellen

Oracle hat eine eingebaute Funktion, um den Inhalt einer Tabelle als XML abzurufen:

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>

Sie können Ihre eigenen Tags darum herum hinzufügen; könnte als Abfrage erfolgen, aber da Sie eine gespeicherte Prozedur wünschen:

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>

Das hat also die gewünschte Struktur (na ja, denke ich, aber siehe unten), hat aber ROWSET und ROW statt RECORDS und RECORD . Das vielleicht Egal, es hängt davon ab, ob Sie das Format für diese Schnittstelle noch entwickeln. Wenn es darauf ankommt, können Sie einen weiteren Schritt anwenden, um diese Knoten umzubenennen , oder - hilfreicher - verwenden Sie dbms_xmlgen Prozeduren setrowsettag und setrowtag , was in Ihrem Verfahren einfach ist (und unten gezeigt wird).

Ich nehme an, was Sie als <TABLENAME></TABLENAME> angezeigt haben war ein Fehler, und Sie möchten die Datensätze in diesem Tag. Wenn nicht, und Sie möchten das aus irgendeinem Grund wirklich, ändern Sie die Abfrage in der Funktion in:

  select xmlelement("XML",
      xmlconcat(xmlelement(evalname(table_name), null),
      dbms_xmlgen.getxmltype('select * from "' || table_name || '"')))
  into xml
  from dual;

Sie können das dann wie gewohnt in eine Datei schreiben; Wenn Sie von SQL*Plus usw. aufrufen, können Sie auswählen und spoolen, oder wenn Sie überhaupt nicht möchten, dass es zurückgegeben wird, können Sie UTL_FILE hinzufügen Direktive, um die Datei innerhalb der Prozedur zu schreiben, aber das müsste in ein Verzeichnisobjekt auf dem DB-Server erfolgen, was möglicherweise nicht bequem ist.

Meistens zu meinem eigenen Vorteil, da ich nicht viel mit XML mache:

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;
/

Bei Ausführung mit exec table_to_xml_file('T42') , erzeugt dies eine Datei namens T42.xml im Serververzeichnis, auf das durch <directory> verwiesen wird Verzeichnisobjekt, das Folgendes enthält:

<XML>
  <T42>
    <RECORDS>
      <RECORD>
        <ID>1</ID>
        <STR>AA</STR>
      </RECORD>
      <RECORD>
        <ID>2</ID>
        <STR>BB</STR>
      </RECORD>
    </RECORDS>
  </T42>
</XML>

Übrigens habe ich den Tabellennamen im select in dbms_xmlgen.getxmltype in doppelte Anführungszeichen gesetzt Anruf. Das dient dazu, die Anforderung „Groß- und Kleinschreibung sollte dieselbe sein wie in der Datenbank“ für den Tabellennamen zu erfüllen. es muss im richtigen Fall an die Prozedur übergeben werden, sonst wird es einen Fehler geben. Das ist einfacher, als zu versuchen, den Fall innerhalb der Prozedur irgendwie zu korrigieren, was umständlich oder unmöglich wäre, wenn Sie neben dem Fall zwei Tabellen mit demselben Namen hätten. Die Spaltennamen werden sowieso korrekt geschrieben.