sql >> Database >  >> RDS >> Oracle

genereer XML uit orakeltabellen

Oracle heeft een ingebouwde functie om de inhoud van een tabel als XML te krijgen:

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>

Je kunt daar je eigen tags omheen toevoegen; kan worden gedaan als een query, maar aangezien u een opgeslagen procedure wilt:

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>

Dus dit heeft de structuur die je wilt (nou ja, ik denk, maar zie hieronder), maar heeft ROWSET en ROW in plaats van RECORDS en RECORD . Dat misschien maakt niet uit, het hangt ervan af of je het formaat voor deze interface nog aan het ontwikkelen bent. Als het er toe doet, kun je een volgende stap toepassen om die knooppunten te hernoemen , of - handiger - gebruik de dbms_xmlgen procedures setrowsettag en setrowtag , wat eenvoudig is in uw procedure (en hieronder wordt gedemonstreerd).

Ik neem aan wat je hebt laten zien als <TABLENAME></TABLENAME> was een vergissing en u wilt de records binnen die tag. Als dat niet het geval is, en je wilt dat om de een of andere reden echt, verander dan de query in de functie in:

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

Je kunt dat dan op een normale manier naar een bestand schrijven; als u belt vanuit SQL*Plus enz. kunt u selecteren en spoolen, of als u het helemaal niet wilt retourneren, kunt u UTL_FILE toevoegen instructie om het bestand vanuit de procedure te schrijven, maar dat zou naar een directory-object op de DB-server moeten zijn, wat misschien niet handig is.

Meestal voor mijn eigen voordeel aangezien ik niet veel met XML doe:

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

Wanneer uitgevoerd met exec table_to_xml_file('T42') , dit levert een bestand op met de naam T42.xml in de serverdirectory waarnaar wordt verwezen door de <directory> directory-object, dat het volgende bevat:

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

Overigens heb ik dubbele aanhalingstekens geplaatst rond de tabelnaam in de select in het dbms_xmlgen.getxmltype telefoongesprek. Dat is om te voldoen aan de eis 'case zou hetzelfde moeten zijn als in database' voor de tabelnaam; het moet in het juiste geval aan de procedure worden doorgegeven, anders zal het fout gaan. Dat is eenvoudiger dan op de een of andere manier proberen de casus binnen de procedure te corrigeren, wat onhandig of onmogelijk zou zijn als je twee tabellen met dezelfde naam had naast de casus. De kolomnamen zullen hoe dan ook in het juiste geval staan.




  1. verander de onderscheidende waarde van kolommen in een rijen postgres

  2. Langzame MySQL-query

  3. Verschil tussen TRIM() en TRIM_ORACLE() in MariaDB

  4. een array maken uit de database