1. 程式人生 > >PLSQL解析XML檔案

PLSQL解析XML檔案

參考網上資料學習彙總

在PL/SQL中利用XML ,Oracle提供了幾個元件,讓開發人員能輕鬆地利用XML技術。這些元件包括:

 1.  XML 分析程式。即用來分析、構造和驗證XML文件。.

2. XPath 引擎。 它是使用Xpath(XML標準的另一個元素)說明語法在記憶體中搜索XML文件的實用程式。 SLT 處理器。 它在Oracle資料庫中支援XSLT,允許您把XML文件轉換成其他格式。

3. XML SQL 實用程式。可以使用SQL產生XML文件,使您可以在Oracle資料庫表格中輕鬆地插入基於XML的資料。 XSQL 頁。一項可以彙集宣告性XML資料然後通過XSLT公佈這些資料的技術。 對於PL/SQL開發人員而言,XML分析程式是最重要的元件。通過它,您可以在Oracle資料庫中分析、操縱和轉換XML文件。ML分析程式由一套APIs(應用程式程式設計介面)構成。

XML結構

XML常用分析函式

XMLParser

包括分析XML文件所需的資料型別和程式。XML Parsing Process

 

 

想知道Oracle的parser是如何呼叫Java來做解析的,請檢視Oracle® XMLDeveloper's Kit Programmer's Guide
10g Release 2 (10.2)
Part Number B14252-01

網址: http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14252/adx_j_parser.htm#i1013320

程式中常用的方法:

Nodelist := dbms_xslprocessor.selectnodes(rootnode, xpath)

dbms_xslprocessor.valueof(節點,節點下的元素,值)

XMLDOM


包括管理和建立XML文件物件模型(DOM)元素所需的資料型別和程式

Comparing DOM (Tree-Based) and SAX (Event-Based) APIs

XMLDOM 這個程式包,其實是通過封裝Java 程式來解析XML 的一個PL/SQL的包。具體的作用還是要參考Oracle® Database PL/SQLPackages and Types Reference
10g Release 2 (10.2)
Part Number B14258-02

網址: http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_xmldom.htm

例項
 

<?xml version="1.0" encoding="UTF-8"?>
<Dfile Status="3">
<RecCount>200</RecCount>
<FailCount>1</FailCount>
 <FailInfo>
  <FItem RecErrCode="2901">
     <Item>
       <Name>名稱1</Name>
       <Comment>中國銀行</Comment>
     </Item>
     <Item>
       <Name>名稱2</Name>
       <Comment>建設銀行</Comment>
     </Item>
  </FItem>
 </FailInfo>
 <FailInfo>
  <FItem RecErrCode="2902">
     <Item>
       <Name>名稱3</Name>
       <Comment>招商銀行</Comment>
     </Item>
     <Item>
       <Name>名稱4</Name>
       <Comment>平安銀行</Comment>
     </Item>
     <Item>
       <Name>名稱5</Name>
       <Comment>工商銀行</Comment>
     </Item>
  </FItem>
 </FailInfo>

檔案的結構

解析方案


在XML DOM的解析過程中, 如果想找某個節點(Fitem)的屬性(RecErrCode),而該節點又不是根節點時,需要從最小的節點往上找父節點,一直到節點Fitem,然後在得到其屬性。如果節點是根節點,則可以直接得到根節點的元素和屬性的值。

根據上圖所示,我們要找根節點Dfile的元素和屬性的值,直接呼叫

Oracle通過呼叫API xmldom和dbms_xmlparser來做XML檔案的解析。

1. 建立一個Directory ,假如在EBS上實現則需要在EBS DB的伺服器上建立路徑 如:

  CreateOr Replace Directory FTP_XXX As '/var/tmp/ftp' 直接在APPS下就可以新建

要查詢當前建立的Directory 可以使用 Select * From all_directories 查詢當前系統中的所有的 Directory .
 

 

DECLARE
  p_max_size NUMBER := dbms_lob.lobmaxsize;
  src_offset NUMBER := 1;
  dst_offset NUMBER := 1;
  lang_ctx   NUMBER := nls_charset_id('UTF8');
  default_csid CONSTANT INTEGER := nls_charset_id('ZHS16GBK');
  warning         NUMBER;
  l_file_number   PLS_INTEGER := 0;
  l_count         NUMBER;
  l_bfile         BFILE;
  l_clob          CLOB;
  l_commitelement xmldom.domelement;
  l_parser        dbms_xmlparser.parser;
  l_doc           dbms_xmldom.domdocument;
  l_nl            dbms_xmldom.domnodelist;
  l_n             dbms_xmldom.domnode;
  rootnode        dbms_xmldom.domnode;
  parent_rootnode dbms_xmldom.domnode;
  file_length     NUMBER;
  block_size      BINARY_INTEGER;
  l_rootnode_name VARCHAR2(200);
  l_status        VARCHAR2(1000);
  l_recerrcode    VARCHAR2(1000);
  l_failcount     VARCHAR2(200);
  l_reccount      VARCHAR2(200);
  l_name          VARCHAR2(1000);
  l_comments      VARCHAR2(2000);
  l_exists        BOOLEAN;
 
  FUNCTION convertclobtoxmlelement(p_document IN CLOB)
    RETURN xmldom.domelement IS
    x_commitelement xmldom.domelement;
    l_parser        xmlparser.parser;
  BEGIN
    l_parser := xmlparser.newparser;
    xmlparser.parseclob(l_parser, p_document);
    x_commitelement := xmldom.getdocumentelement(xmlparser.getdocument(l_parser));
    RETURN x_commitelement;
  END convertclobtoxmlelement;
BEGIN
  -- 檢查XML是否在路徑FTP_XXX下是否存在
  utl_file.fgetattr('FTP_XXX',
                    'simanhe_test.xml',
                    l_exists,
                    file_length,
                    block_size);
 
  IF NOT l_exists THEN
    dbms_output.put_line('XML檔案不存在');
    RETURN;
  END IF;
 
  l_bfile := bfilename('FTP_XXX', 'simanhe_test.xml');
  -- 建立一個Clob
  dbms_lob.createtemporary(l_clob, TRUE);
  dbms_lob.open(l_bfile, dbms_lob.lob_readonly);
  -- 將XML檔案上載並轉換為Clob型別
  dbms_lob.loadclobfromfile(l_clob,
                            l_bfile,
                            p_max_size,
                            dst_offset,
                            src_offset,
                            default_csid, -- UTF8
                            lang_ctx, -- GBK
                            warning);
  l_file_number := dbms_lob.fileexists(l_bfile);
  IF l_file_number = 0 THEN
    dbms_output.put_line('XML檔案未被轉換成功');
    RETURN;
  END IF;
  dbms_lob.close(l_bfile);
  -- Create a parser.
  l_parser := dbms_xmlparser.newparser;
  BEGIN
    -- Parse the document and create a new DOM document.
    dbms_xmlparser.parseclob(l_parser, l_clob);
  EXCEPTION
    WHEN OTHERS THEN
      dbms_output.put_line('XML檔案不完整');
      RETURN;
  END;
  l_doc := dbms_xmlparser.getdocument(l_parser);
  -- Free resources associated with the CLOB and Parser now they are no longer needed.
  dbms_lob.freetemporary(l_clob);
  -- 得到根節點 
  rootnode        := xmldom.makenode(xmldom.getdocumentelement(xmlparser.getdocument(l_parser)));
  l_rootnode_name := xmldom.getnodename(rootnode);
  dbms_output.put_line('XML檔案當前的節點名稱為 ' || l_rootnode_name);
  -- 得到根節點元素的值
  dbms_xslprocessor.valueof(rootnode, 'RecCount/text()', l_reccount);
  dbms_xslprocessor.valueof(rootnode, 'FailCount/text()', l_failcount);
  dbms_output.put_line('XML檔案當前的節點名稱為 ' || l_rootnode_name ||
                       '的要素RecCount,FailCount值為' || l_reccount || ',' ||
                       l_failcount);
  -- 得到根節點Dfile的屬性Status的值
  l_status := xmldom.getattribute(xmldom.makeelement(rootnode), 'Status');
  dbms_output.put_line('XML檔案當前的節點名稱為 ' || l_rootnode_name ||
                       '的屬性Status的值為' || l_status);
 
  /*取節點Item下各元素的值,先將Items節點全部存放在 l_nl中 */
  l_nl    := dbms_xmldom.getelementsbytagname(l_doc, 'Item');
  l_count := dbms_xmldom.getlength(l_nl);
  FOR cur_emp IN 0 .. dbms_xmldom.getlength(l_nl) - 1 LOOP
    l_n := dbms_xmldom.item(l_nl, cur_emp);
    -- 得到節點Item下元素的值
    dbms_xslprocessor.valueof(l_n, 'Name/text()', l_name);
    dbms_xslprocessor.valueof(l_n, 'Comment/text()', l_comments);
    -- 得到節點Item的父節點FItem
    parent_rootnode := dbms_xmldom.getparentnode(l_n);
    l_rootnode_name := xmldom.getnodename(parent_rootnode);
    -- 得到節點FItem的屬性RecErrCode的值
    l_recerrcode := xmldom.getattribute(xmldom.makeelement(parent_rootnode),
                                        'RecErrCode');
  
    dbms_output.put_line('Name :' || l_name || ' ,Comment = ' ||
                         l_comments || ' ,RecErrCode = ' || l_recerrcode);
  
  END LOOP;
  -- 釋放分析函式的資源
  dbms_xmlparser.freeparser(l_parser);
  -- 將DOC清空,釋放資源
  dbms_xmldom.freedocument(l_doc);
  /*  utl_file.frename('FTP_XXX',
  'simanhe_test.xml',
  'FTP_XXX',
  'D_simanhe_test.xml',
  FALSE);*/ -- XML檔案解析完成後重新命名
  /*utl_file.fremove('FTP_XXX', 'simanhe_test.xml'); */ -- -- XML檔案解析完成後刪除檔案
EXCEPTION
  WHEN OTHERS THEN
    dbms_lob.freetemporary(l_clob);
    dbms_xmlparser.freeparser(l_parser);
    dbms_xmldom.freedocument(l_doc);
END;