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;