、 引言
本文主要阐述一种在ORACLE中解析XML的实现方法。在oracle8i以及后期的版本中,开始提供了xmldom方式来实现对XML格式数据的处理,但在实际的业务信息系统应用开发中,更多的都习惯在程序中(如java,.net等开发语言提供的xml组件)来解析XML数据,很少直接在ORACLE数据库中来直接解析XML数据。
2、 现象描述
当前,XML数据格式越来越多的应用于各种业务信息系统以及数据交换等应用范围,XML数据变得更加常见以及应用更为广泛。在oracle8i以及后期的版本中,开始提供了xmldom方式来实现对XML格式数据的处理,但在实际的业务信息系统应用开发中,更多的都习惯在程序中(如java,.net等开发语言提供的xml组件)来解析XML数据,很少直接在ORACLE数据库中来直接解析XML数据。
3、 处理过程
XML数据可以为字符串(适合处理较小的xml数据)、物理文件或CLOB字段(处理较大的xml数据字段);以如下的XML数据为例来描述该解析处理过程。
XML数据格式示例如下:
<?<xmlversion="1.0" encoding="GBK" ?>
- <items>
- <unit>
- <item>
<name>单位名称</name>
<value>JXDL</value>
</item>
- <item>
<name>年新增归档数</name>
<value>330</value>
</item>
</unit>
</</items>
步骤1:定义或确定要解析的XML规则,如上。
步骤2:创建XML解析器实例XMLPARSER.parser,如下:
xmlPar XMLPARSER.parser := XMLPARSER.NEWPARSER;
步骤3:定义DOM文档对象,如下:
doc xmldom.DOMDocument;
步骤4:定义解析XML所需要的其他对象,如下:
lenUnit integer;
lenIteminteger;
unitNodesxmldom.DOMNodeList;
itemNodesxmldom.DOMNodeList;
chilNodesxmldom.DOMNodeList;
tempNode_unitxmldom.DOMNode;
tempNodexmldom.DOMNode;
tempArrMapxmldom.DOMNamedNodeMap;
--================================
--以下变量用于获取XML节点的值
name varchar2(50);
value varchar2(20);
tmp integer;
--================================
xmlClobDataclob;
步骤5:获取xml数据,以下假设从数据表的clob字段中获取取,如下:
selectdatastring into xmlClobData from p_xml_datainfo t where …… ;
步骤6:解析xml数据,如下
xmlPar := xmlparser.newParser;
--xmlparser.parseBuffer(xmlPar,xmlString);--
xmlparser.parseClob(xmlPar,xmlClobData);
doc :=xmlparser.getDocument( xmlPar );
-- 释放解析器实例
xmlparser.freeParser(xmlPar);
-- 获取所有unit元素
unitNodes := xmldom.getElementsByTagName( doc, 'unit' );
lenUnit := xmldom.getLength( unitNodes );
--遍历所有unit元素
FOR iin 0..lenUnit-1
LOOP
--获取第i个unit
tempNode_unit := xmldom.item( unitNodes, i );
itemNodes:=xmldom.getChildNodes(tempNode_unit);
lenItem := xmldom.getLength( itemNodes );
FOR j in 0..lenItem-1
LOOP
tempNode := xmldom.item( itemNodes, j );
--获取子元素的值
chilNodes := xmldom.getChildNodes(tempNode);
tmp := xmldom.GETLENGTH( chilNodes );
name := xmldom.getNodeValue(xmldom.getFirstChild(xmldom.item( chilNodes, 0 )));
value := xmldom.getNodeValue(xmldom.getFirstChild(xmldom.item( chilNodes, 1)));
DBMS_output.PUT_LINE(i||j,name,value);
end loop;
END LOOP;
步骤7:释放文档对象
xmldom.freeDocument(doc);
步骤8:异常与错误处理
EXCEPTION
WHEN OTHERS THEN
DBMS_output.PUT_LINE(SQLERRM);
4、 原因分析
目前,在实际的业务信息系统应用开发中,更多的都习惯在程序中(如java,.net等开发语言提供的xml组件)来解析XML数据,很少直接在ORACLE数据库中来直接解析XML数据。
5、 经验总结
通过在ORACLE数据库中直接解析XML数据,能够更方便灵活的处理xml数据,包括创建方法function,存储过程procedure,以及作业JOB,尤其是处理已经存储在数据表中的XML数据。
示例:
CREATE OR REPLACE PROCEDURECRM_TEMP.P_sys_EmployeesRoleInsert
(
strxml VARCHAR2,
CreateID VARCHAR2,
CreateIP VARCHAR2,
CreateMacAddress VARCHAR2,
CurApmodelID VARCHAR2,
HRSiteID VARCHAR2
)
IS
tmpVar NUMBER;
xmlParXMLPARSER.parser := XMLPARSER.NEWPARSER;
docxmldom.DOMDocument;
pNodesxmldom.DOMNodeList;
tempNodexmldom.DOMNode;
tempArrMapxmldom.DOMNamedNodeMap;
tempRolelIDnvarchar2(128);
tempWorkNOnvarchar2(128);
len int;
n int ;
v_RoleModelIDNVARCHAR2(128);
v_RolelID NVARCHAR2(128);
v_APModelID NVARCHAR2(128);
v_FunctionCode NVARCHAR2(128);
v_PAPModelID NVARCHAR2(128);
v_Count NVARCHAR2(64);
I_CreateID NVARCHAR2(128);
I_CreateIP NVARCHAR2(128);
I_CreateMacAddress NVARCHAR2(128);
I_CurApmodelID NVARCHAR2(128);
I_HRSiteID NVARCHAR2(128);
BEGIN
IF strxml is not null THEN
BEGIN
I_CreateID :=CreateID;
I_CreateIP :=CreateIP;
I_CreateMacAddress :=CreateMacAddress;
I_CurApmodelID :=CurApmodelID;
I_HRSiteID :=HRSiteID;
v_Count := 0;
XMLPARSER.PARSECLOB(xmlPar,strxml);
doc:=XMLPARSER.getDocument( xmlPar );
XMLPARSER.FREEPARSER(xmlPar);
pNodes:=xmldom.getElementsByTagName(doc, 'tempWorkNO' );
len:=xmldom.getLength(pNodes);
tempNode := xmldom.item( pNodes, 0 );
tempArrMap := xmldom.getAttributes(tempNode);
tempRolelID:=xmldom.getNodeValue(xmldom.getNamedItem(tempArrMap,'tempRolelID'));
tempWorkNO := xmldom.getNodeValue(xmldom.getNamedItem(tempArrMap,'tempWorkNO'));
DELETE
FROM Sys_RoleEmployees a
WHERE a.WORKNO = tempWorkNO AND a.HRSiteID=I_HRSiteID;
FOR i in 0..len-1
LOOP
tempNode := xmldom.item( pNodes, i );
tempArrMap := xmldom.getAttributes(tempNode);
tempRolelID:=xmldom.getNodeValue(xmldom.getNamedItem(tempArrMap,'tempRolelID'));
tempWorkNO := xmldom.getNodeValue(xmldom.getNamedItem(tempArrMap,'tempWorkNO'));
INSERT INTO Sys_RoleEmployees
(
RoleEmployeesID,
RolelID,
WORKNO,
createID,
CreateIP,
CreateMacAddress,
CurApmodelID,
HRSiteID
)
VALUES
(
SYS_GUID(),
tempRolelID,
tempWorkNO,
I_CreateID,
I_CreateIP,
I_CreateMacAddress,
I_CurApmodelID,
I_HRSiteID
);
Commit;
END LOOP;
END;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END P_sys_EmployeesRoleInsert;
/
示例2.
1 <?xml version="1.0"?>
2 <PEOPLE>
3 <PERSON PERSONID="E01">
4 <NAME>Tony Blair</NAME>
5 <ADDRESS>10 Downing Street, London, UK</ADDRESS>
6 <TEL>(061) 98765</TEL>
7 <FAX>(061) 98768</FAX>
8 <EMAIL>blair@everywhere.com</EMAIL>
9 </PERSON>
10 <PERSON PERSONID="E02">
11 <NAME>Bill Clinton</NAME>
12 <ADDRESS>White House, USA</ADDRESS>
13 <TEL>(001) 6400 98765</TEL>
14 <FAX>(001) 6400 98769</FAX>
15 <EMAIL>bill@everywhere.com</EMAIL>
16 </PERSON>
17 <PERSON PERSONID="E03">
18 <NAME>Tom Cruise</NAME>
19 <ADDRESS>57 Jumbo Street, New York, USA</ADDRESS>
20 <TEL>(001) 4500 67859</TEL>
21 <FAX>(001) 4500 67895</FAX>
22 <EMAIL>cruise@everywhere.com</EMAIL>
23 </PERSON>
24 <PERSON PERSONID="E04">
25 <NAME>Linda Goodman</NAME>
26 <ADDRESS>78 Crax Lane, London, UK</ADDRESS>
27 <TEL>(061) 54 56789</TEL>
28 <FAX>(061) 54 56772</FAX>
29 <EMAIL>linda@everywhere.com</EMAIL>
30 </PERSON>
31 </PEOPLE>
我以scott用户为例,新建表:
1 CREATE TABLE PEOPLE
2 (
3 PERSONID VARCHAR2(4) PRIMARY KEY,
4 NAME VARCHAR2(50),
5 ADDRESS VARCHAR2(200),
6 TEL VARCHAR2(20),
7 FAX VARCHAR2(20),
8 EMAIL VARCHAR2(100)
9 );
解析并持久化的存储过程代码:
*file_path 需要解析的XML文件路径 如:D:\OracleTest\people.xml
3 *log_path 保存日志的文件的路径 如: D:\OracleTest\xmllog.txt
4 **/
5
6 CREATE OR REPLACE PROCEDURE addPerson(file_path VARCHAR2,log_path VARCHAR2)
7 AS
8 --//XML解析器
9 xmlPar XMLPARSER.parser := XMLPARSER.NEWPARSER;
10 --//DOM文档对象
11 doc xmldom.DOMDocument;
12 len integer;
13 personNodes xmldom.DOMNodeList;
14 chilNodes xmldom.DOMNodeList;
15 tempNode xmldom.DOMNode;
16 tempArrMap xmldom.DOMNamedNodeMap;
17 --================================
18 --以下变量用于获取XML节点的值
19 pid varchar2(4);
20 name varchar2(50);
21 address varchar2(200);
22 tel varchar2(20);
23 fax varchar2(20);
24 email varchar(100);
25 tmp integer;
26 --================================
27 BEGIN
28 xmlPar := xmlparser.newParser;
29 xmlparser.setErrorLog( xmlPar, log_path);
30 xmlparser.parse(xmlPar, file_path);
31 doc := xmlparser.getDocument( xmlPar );
32 -- 释放解析器实例
33 xmlparser.freeParser(xmlPar);
34 -- 获取所有PERSON元素
35 personNodes := xmldom.getElementsByTagName( doc, 'PERSON' );
36 len := xmldom.getLength( personNodes );
37 --遍历所有PERSON元素
38 FOR i in 0..len-1
39 LOOP
40 --获取第i个PERSON
41 tempNode := xmldom.item( personNodes, i );
42 --所有属性
43 tempArrMap := xmldom.getAttributes(tempNode);
44 --获取PERSONID的值
45 pid := xmldom.getNodeValue(xmldom.getNamedItem(tempArrMap,'PERSONID'));
46 --获取子元素的值
47 chilNodes := xmldom.getChildNodes(tempNode);
48 tmp := xmldom.GETLENGTH( chilNodes );
49 name := xmldom.getNodeValue(xmldom.getFirstChild(xmldom.item( chilNodes, 0 )));
50 address := xmldom.getNodeValue(xmldom.getFirstChild(xmldom.item( chilNodes, 1 )));
51 tel := xmldom.getNodeValue(xmldom.getFirstChild(xmldom.item( chilNodes, 2 )));
52 fax := xmldom.getNodeValue(xmldom.getFirstChild(xmldom.item( chilNodes, 3 )));
53 email := xmldom.getNodeValue(xmldom.getFirstChild(xmldom.item( chilNodes, 4 )));
54 --插入数据
55 INSERT INTO PEOPLE VALUES (pid,name,address,tel,fax,email);
56 COMMIT;
57 END LOOP;
58 -- 释放文档对象
59 xmldom.freeDocument(doc);
60 EXCEPTION
61 WHEN OTHERS THEN
62 DBMS_output.PUT_LINE(SQLERRM);
63 END addPerson;