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;