From XML inside CLOB, to Oracle table with list of paths

房东的猫 提交于 2019-12-12 08:14:20

问题


The Oracle Version I am using is:

BANNER
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE    10.2.0.4.0  Production
TNS for IBM/AIX RISC System/6000: Version 10.2.0.4.0 - Productio
NLSRTL Version 10.2.0.4.0 - Production

In a previous question, I've asked how to transform a clob into a table, see this:

From XML to list of paths in Oracle PL/SQL environment

The answer I received was great, and it works for XML not too big.

But if I have a table called MY_TABLE_ONE with a field called MY_FIELD which is a CLOB with a very large content (for example 500 Kbytes), the following statement WON'T exit in a reasonable time:

CREATE TABLE MY_TABLE_TWO
AS
   WITH PARAMS AS (SELECT   XMLTYPE (MY_FIELD) FROM MY_TABLE_ONE)
   SELECT   ELEMENT_PATH, ELEMENT_TEXT
     FROM   XMLTABLE (
               '              
      for $i in $doc/descendant-or-self::*
        return <element>
                 <element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
                 <element_content> {$i/text()}</element_content>
               </element>  
    '
                  PASSING (SELECT   * FROM PARAMS) AS "doc"
                  COLUMNS ELEMENT_PATH VARCHAR2 (4000) PATH '//element_path',
                          ELEMENT_TEXT VARCHAR2 (4000) PATH '//element_content'
            );

Is there any alternative way to transform an XML stored inside CLOB column, in an Oracle table with the list of the paths and the respective values, in a more EFFICIENT way?

The above statement is right, but it needs too much time to finalize.

Thank you very much for considering my request.

EDIT:

I've tried with this iterative solution, with NO SUCCESS :-(

BEGIN
   DECLARE
      CURSOR S_CUR
      IS
         WITH PARAMS AS (SELECT   XMLTYPE (MY_FIELD) FROM MY_TABLE_ONE)
         SELECT   ELEMENT_PATH, ELEMENT_TEXT
           FROM   XMLTABLE (
                     '              
      for $i in $doc/descendant-or-self::*
        return <element>
                 <element_path> {$i/string-join(ancestor-or-self::*/name(.), ''/'')} </element_path>
                 <element_content> {$i/text()}</element_content>
               </element>  
    '
                        PASSING (SELECT   * FROM PARAMS where rownum < 101) AS "doc"
                        COLUMNS ELEMENT_PATH VARCHAR2 (4000) PATH '//element_path',
                                ELEMENT_TEXT VARCHAR2 (4000) PATH '//element_content'
                  );

      TYPE FETCH_ARRAY IS TABLE OF S_CUR%ROWTYPE;

      S_ARRAY   FETCH_ARRAY;
   BEGIN
      EXECUTE IMMEDIATE 'ALTER SESSION SET DB_FILE_MULTIBLOCK_READ_COUNT=256';

      EXECUTE IMMEDIATE 'TRUNCATE TABLE GOOFY99 DROP STORAGE';

      OPEN S_CUR;

      LOOP
         FETCH S_CUR
         BULK COLLECT INTO   S_ARRAY
         LIMIT 500;

         FORALL I IN 1 .. S_ARRAY.COUNT
            INSERT                                                  /*+APPEND */
                  INTO GOOFY99
            VALUES   S_ARRAY (I);

         COMMIT;
         EXIT WHEN S_CUR%NOTFOUND;
      END LOOP;

      CLOSE S_CUR;

      COMMIT;
   END;
END;

回答1:


UPD I found quite big xml file (140 KB). My sistem: notebook with core i5 processor (2400 MHz), oracle 12c inside a virtual machine, time to process - 0.38 seconds. This method is the only alternative that I know. Example of xml here I found at w3schools.com.

declare
  xml_str clob := q'[<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
 <CD>
  <TITLE>Empire Burlesque</TITLE>
  <ARTIST>Bob Dylan</ARTIST>
  <COUNTRY>USA</COUNTRY>
  <COMPANY>Columbia</COMPANY>
  <PRICE>10.90</PRICE>
  <YEAR>1985</YEAR>
 </CD>
 <CD>
  <TITLE>Hide your heart</TITLE>
  <ARTIST>Bonnie Tyler</ARTIST>
  <COUNTRY>UK</COUNTRY>
  <COMPANY>CBS Records</COMPANY>
  <PRICE>9.90</PRICE>
  <YEAR>1988</YEAR>
 </CD>
</CATALOG>]';

v_doc  dbms_xmldom.domdocument;
node   dbms_xmldom.domnode;
txt    varchar2(4000);
type   t_list is table of number index by varchar2(4000);
v_list t_list;
  procedure enum_nodes(n dbms_xmldom.domnode, tag_name varchar2) is
    chn  dbms_xmldom.domnode;
    nl   dbms_xmldom.domnodelist;
  begin
    nl := dbms_xmldom.getchildnodes(n);
    for i in 0..dbms_xmldom.getlength(nl) loop
      chn := dbms_xmldom.item(nl, i);

      if dbms_xmldom.getnodetype(chn) = 1 then
         enum_nodes(chn, tag_name || dbms_xmldom.getnodeName(chn) || '/');
      elsif dbms_xmldom.getnodetype(chn) = 3 then
         v_list(tag_name || dbms_xmldom.getnodevalue(chn)) := 1;
      end if;
    end loop;
  end;
begin
  v_doc := dbms_xmldom.newdomdocument(xml_str);
  node := dbms_xmldom.makenode(v_doc);

  enum_nodes(node, '/');

  txt := v_list.first;
  while txt is not null loop
     dbms_output.put_line(txt);
     txt := v_list.next(txt);
  end loop;
end;
/


来源:https://stackoverflow.com/questions/26753055/from-xml-inside-clob-to-oracle-table-with-list-of-paths

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!