Phân tích XML trong Oracle PL/SQL
Xem thêm các chuyên mục:

Là một website được viết trên công nghệ web Flutter vì vậy hỗ trợ rất tốt cho người học, kể cả những người học khó tính nhất.
Hiện tại website đang tiếp tục được cập nhập nội dung cho phong phú và đầy đủ hơn. Mong các bạn nghé thăm và ủng hộ website mới của chúng tôi.


Tài liệu được viết dựa trên:
-
Oracle 9i (10g,11g, 12c)
Oracle cung cấp 2 API cơ bản để phân tích (parse) XML:
- DOM (Document Object Model)
- XSLT & XPath
Bạn có thể phân tích một tài liệu XML với nguồn dữ liệu từ:
- Nguồn dữ liệu XML là một file.
- Nguồn dữ liệu là văn bản (varchar2,..)
- Nguồn dữ liệu là CLOB
Ví dụ phân tích một tài liệu XML đơn giản (Nguồn văn bản):
Parse_Xml_Example
Create Or Replace Procedure Parse_Xml_Example As
p Dbms_Xmlparser.Parser;
v_Doc Dbms_Xmldom.Domdocument;
v_Root_Element Dbms_Xmldom.Domelement;
v_Child_Nodes Dbms_Xmldom.Domnodelist;
v_Child_Node Dbms_Xmldom.Domnode;
v_Text_Node Dbms_Xmldom.Domnode;
v_Emp_Nodes Dbms_Xmldom.Domnodelist;
v_Emp_Node Dbms_Xmldom.Domnode;
---
v_Xml_Data Varchar2(4000);
v_Deptno Varchar2(30);
v_Dname Varchar2(100);
v_Location Varchar2(255);
v_Empno Varchar2(30);
v_Ename Varchar2(100);
v_Job Varchar2(100);
v_Hiredate Date;
v_Mrg Number;
v_Sal Number;
--
v_Attr_Nodes Dbms_Xmldom.Domnamednodemap;
v_Attr_Node Dbms_Xmldom.Domnode;
v_Attribute_Name Varchar2(50);
v_Node_Name Varchar2(50);
v_Node_Value Varchar2(100);
Begin
-- Text không chứa <?xml version="1.0"?>
v_Xml_Data := '<department deptno="10" dname="ACCOUNTING" location="NEW YORK">
<employee empno="7782" ename="CLARK">
<job>MANAGER</job>
<mrg>7839</mrg>
<hiredate>6/9/1981</hiredate>
<sal>2450.00</sal>
</employee>
<employee empno="7839" ename="KING">
<job>PRESIDENT</job>
<mrg></mrg>
<hiredate>11/17/1981</hiredate>
<sal>5000.00</sal>
</employee>
<employee empno="7934" ename="MILLER">
<job>CLERK</job>
<mrg>7782</mrg>
<hiredate>1/23/1982</hiredate>
<sal>1300.00</sal>
</employee>
</department>';
-- Tạo một bộ phân tích XML
p := Dbms_Xmlparser.Newparser;
Dbms_Xmlparser.Setvalidationmode(p
,False);
-- Parse XML into DOM object
Dbms_Xmlparser.Parsebuffer(p
,v_Xml_Data);
-- Lấy ra đối tượng Dbms_xmldom.Domdocument
-- (Phần tử mô tả toàn bộ tài liệu)
v_Doc := Dbms_Xmlparser.Getdocument(p);
-- Phần tử gốc của tài liệu (<department>)
v_Root_Element := Dbms_Xmldom.Getdocumentelement(v_Doc);
-- Lấy giá trị của các thuộc tính
v_Deptno := Dbms_Xmldom.Getattribute(v_Root_Element
,'deptno');
v_Dname := Dbms_Xmldom.Getattribute(v_Root_Element
,'dname');
v_Location := Dbms_Xmldom.Getattribute(v_Root_Element
,'location');
---------
Dbms_Output.Put_Line('v_Deptno=' || v_Deptno);
Dbms_Output.Put_Line('v_Dname=' || v_Dname);
Dbms_Output.Put_Line('v_Location=' || v_Location);
--------
-- Danh sách các Node "employee" của v_Root_Element (Dbms_xmldom.Domnodelist)
v_Emp_Nodes := Dbms_Xmldom.Getelementsbytagname(v_Root_Element
,'employee');
For j In 0 .. Dbms_Xmldom.Getlength(v_Emp_Nodes) Loop
v_Emp_Node := Dbms_Xmldom.Item(v_Emp_Nodes
,j);
-- Attribute List (Dbms_xmldom.Domnamednodemap)
v_Attr_Nodes := Dbms_Xmldom.Getattributes(v_Emp_Node);
--
If (Dbms_Xmldom.Isnull(v_Attr_Nodes) = False) Then
For i In 0 .. Dbms_Xmldom.Getlength(v_Attr_Nodes) - 1 Loop
v_Attr_Node := Dbms_Xmldom.Item(v_Attr_Nodes
,i);
v_Node_Name := Dbms_Xmldom.Getnodename(v_Attr_Node);
--
If v_Node_Name = 'empno' Then
v_Empno := Dbms_Xmldom.Getnodevalue(v_Attr_Node);
Elsif v_Node_Name = 'ename' Then
v_Ename := Dbms_Xmldom.Getnodevalue(v_Attr_Node);
End If;
End Loop;
Dbms_Output.Put_Line('v_Empno=' || v_Empno);
Dbms_Output.Put_Line('v_Ename=' || v_Ename);
End If;
----
-- Child nodes of employee node.
--
v_Child_Nodes := Dbms_Xmldom.Getchildnodes(v_Emp_Node);
--
For i In 0 .. Dbms_Xmldom.Getlength(v_Child_Nodes) - 1 Loop
-- <job>,<mrg>,<hiredate>,<sal>
v_Child_Node := Dbms_Xmldom.Item(v_Child_Nodes
,i);
v_Node_Name := Dbms_Xmldom.Getnodename(v_Child_Node);
v_Text_Node := Dbms_Xmldom.Getfirstchild(v_Child_Node);
v_Node_Value := Dbms_Xmldom.Getnodevalue(v_Text_Node);
--
If v_Node_Name = 'job' Then
v_Job := v_Node_Value;
Elsif v_Node_Name = 'mrg' Then
v_Mrg := To_Number(v_Node_Value);
Elsif v_Node_Name = 'hiredate' Then
v_Hiredate := To_Date(v_Node_Value
,'MM/dd/yyyy');
Elsif v_Node_Name = 'sal' Then
v_Sal := To_Number(v_Node_Value);
End If;
End Loop;
--
Dbms_Output.Put_Line('v_Job=' || v_Job);
Dbms_Output.Put_Line('v_Mrg=' || v_Mrg);
Dbms_Output.Put_Line('v_Hiredate=' || v_Hiredate);
Dbms_Output.Put_Line('v_Sal=' || v_Sal);
End Loop;
End;
Chạy thủ tục:
begin
-- Call the procedure
parse_xml_example;
end;

Bạn cũng có thể phân tích XML từ nguồn CLOB.
Declare
p Dbms_Xmlparser.Parser;
v_Xml_Clob Clob;
v_Doc Dbms_Xmldom.Domdocument;
v_Root_Element Dbms_Xmldom.Domelement;
v_Child_Nodes Dbms_Xmldom.Domnodelist;
v_Greeting_Node Dbms_Xmldom.Domnode;
v_Text_Node Dbms_Xmldom.Domnode;
v_Text Varchar2(100);
Begin
-- Một dữ liệu CLOB (Có thể từ cột CLOB của bảng).
v_Xml_Clob := '<data><greeting>Hello</greeting></data>';
-- Tạo một bộ phân tích XML
p := Dbms_Xmlparser.Newparser;
-- Phân tích dữ liệu XML thành các đối tượng DOM.
Dbms_Xmlparser.Parseclob(p
,v_Xml_Clob);
-- Lấy ra đối tượng Dbms_xmldom.Domdocument
-- (Phần tử mô tả toàn bộ tài liệu)
v_Doc := Dbms_Xmlparser.Getdocument(p);
-- Phần tử gốc của tài liệu (<data>)
v_Root_Element := Dbms_Xmldom.Getdocumentelement(v_Doc);
-- Danh sách các node con 'greeting'.
v_Child_Nodes := Dbms_Xmldom.Getchildrenbytagname(v_Root_Element
,'greeting');
-- Phần từ đầu tiên trong danh sách.
v_Greeting_Node := Dbms_Xmldom.Item(v_Child_Nodes
,0);
v_Text_Node := Dbms_Xmldom.Getfirstchild(v_Greeting_Node);
-- Hello
v_Text := Dbms_Xmldom.Getnodevalue(v_Text_Node);
--
Dbms_Output.Put_Line('Greeting:' || v_Text);
End;

Trước hết bạn cần tạo ra một thư mục ảo, và gán quyền truy cập vào file trên thư mục đó.
-- Tạo ra một thư mục ảo (Thư mục DBA)
Create Directory MY_XML_DIR as 'C:/TEMP';
-- Gán quyền đọc và ghi trên thư mục này cho user scott.
Grant Read,Write on Directory MY_XML_DIR to scott;


Ví dụ dưới đây phân tích một file xml:

C:/TEMP/company.xml
<company id="111" companyName="Microsoft">
<websites>
<website>http://microsoft.com</website>
<website>http://msn.com</website>
<website>http://hotmail.com</website>
</websites>
<address>
<street>1 Microsoft Way</street>
<city>Redmond</city>
</address>
</company>
Parse_Xml_File_Example
Create Or Replace Procedure Parse_Xml_File_Example As
v_Bfile Bfile;
v_Xml_Clob Clob;
---
p Dbms_Xmlparser.Parser;
v_Doc Dbms_Xmldom.Domdocument;
v_Root_Element Dbms_Xmldom.Domelement;
v_Child_Nodes Dbms_Xmldom.Domnodelist;
v_Child_Node Dbms_Xmldom.Domnode;
v_Text_Node Dbms_Xmldom.Domnode;
v_Text Varchar2(100);
----
v_Dest_Offset Integer := 1;
v_Src_Offset Integer := 1;
v_Lang_Context Number := Dbms_Lob.Default_Lang_Ctx;
v_Warning Integer;
--
v_Value Varchar2(255);
Begin
-- Đối tượng đại diện cho file XML.
v_Bfile := Bfilename('MY_XML_DIR'
,'company.xml');
-- Tạo dữ liệu CLOB rỗng
Dbms_Lob.Createtemporary(v_Xml_Clob
,Cache => False);
-- Mở file XML
Dbms_Lob.Open(v_Bfile
,Dbms_Lob.Lob_Readonly);
-- Tải dữ liệu trong file vào v_Clob.
Dbms_Lob.Loadclobfromfile(v_Xml_Clob -- Dest_Lob IN OUT
,v_Bfile -- Src_Lob In
,Dbms_Lob.Getlength(v_Bfile) -- Amount In
,v_Dest_Offset -- Dest_Offset IN OUT
,v_Src_Offset -- Src_Offset In Out
,Dbms_Lob.Default_Csid -- Bfile_Csid In
,v_Lang_Context -- Lang_Context In Out
,v_Warning -- Warning OUT
);
-- Sau khi đọc xong, đóng lại.
Dbms_Lob.Close(v_Bfile);
--
-- Tạo một bộ phân tích XML
p := Dbms_Xmlparser.Newparser;
--
-- Phân tích dữ liệu XML thành các đối tượng DOM.
Dbms_Xmlparser.Parseclob(p
,v_Xml_Clob);
-- Lấy ra đối tượng Dbms_xmldom.Domdocument
-- (Phần tử mô tả toàn bộ tài liệu)
v_Doc := Dbms_Xmlparser.Getdocument(p);
-- Phần tử gốc của tài liệu (<company>)
v_Root_Element := Dbms_Xmldom.Getdocumentelement(v_Doc);
--
v_Value := Dbms_Xmldom.Getattribute(v_Root_Element
,'id');
Dbms_Output.Put_Line('id=' || v_Value);
v_Value := Dbms_Xmldom.Getattribute(v_Root_Element
,'companyName');
Dbms_Output.Put_Line('companyName=' || v_Value);
--- return Dbms_Xmldom.Domnodelist
v_Child_Nodes := Dbms_Xmldom.Getchildrenbytagname(v_Root_Element
,'*');
For i In 0 .. Dbms_Xmldom.Getlength(v_Child_Nodes) - 1 Loop
v_Child_Node := Dbms_Xmldom.Item(v_Child_Nodes
,i);
--
If Dbms_Xmldom.Getnodename(v_Child_Node) = 'websites' Then
Dbms_Output.Put_Line('Found websites');
-- ...
Elsif Dbms_Xmldom.Getnodename(v_Child_Node) = 'address' Then
Dbms_Output.Put_Line('Found address');
-- ...
End If;
End Loop;
Exception
When Others Then
Dbms_Output.Put_Line(Sqlerrm);
Dbms_Lob.Freetemporary(v_Xml_Clob);
Dbms_Xmlparser.Freeparser(p);
Dbms_Xmldom.Freedocument(v_Doc);
End;
Chạy thủ tục:
begin
-- Call the procedure
parse_xml_file_example;
end;

Oracle Cung cấp cho bạn package Dbms_Xslprocessor giúp bạn truy cập vào dữ liệu XML nhanh chóng và dễ dàng hơn . Hãy xem ví dụ sau:
Declare
v_Xml_Clob Clob;
---
p Dbms_Xmlparser.Parser;
v_Doc Dbms_Xmldom.Domdocument;
v_Root_Element Dbms_Xmldom.Domelement;
v_Child_Nodes Dbms_Xmldom.Domnodelist;
v_Current_Node Dbms_Xmldom.Domnode;
v_Websites_Nodes Dbms_Xmldom.Domnodelist;
--
v_Id Number;
v_Company_Name Varchar2(255);
v_Street Varchar2(255);
v_City Varchar2(50);
v_Note Varchar2(255);
Begin
v_Xml_Clob := '<companies xmlns:my-ns="http://somedomain.com/abc">
<company id="111" companyName="Microsoft">
<websites>
<website>http://microsoft.com</website>
<website>http://msn.com</website>
<website>http://hotmail.com</website>
</websites>
<address>
<street>1 Microsoft Way</street>
<city>Redmond</city>
</address>
<my-ns:note>Microsoft Note</my-ns:note>
</company>
<company id="100" companyName="Apple">
<websites>
<website>http://applet.com</website>
</websites>
<address>
<street>1 Infinite Loop</street>
<city>Cupertino</city>
</address>
<my-ns:note>Apple Note</my-ns:note>
</company>
</companies>';
--
-- Tạo một bộ phân tích XML
p := Dbms_Xmlparser.Newparser;
--
-- Phân tích dữ liệu XML thành các đối tượng DOM.
Dbms_Xmlparser.Parseclob(p
,v_Xml_Clob);
-- Lấy ra đối tượng Dbms_xmldom.Domdocument
-- (Phần tử mô tả toàn bộ tài liệu)
v_Doc := Dbms_Xmlparser.Getdocument(p);
-- Phần tử gốc của tài liệu (<companies>)
v_Root_Element := Dbms_Xmldom.Getdocumentelement(v_Doc);
--- return Dbms_Xmldom.Domnodelist
v_Child_Nodes := Dbms_Xmldom.Getchildrenbytagname(v_Root_Element
,'*');
For i In 0 .. Dbms_Xmldom.Getlength(v_Child_Nodes) - 1 Loop
-- <company> Node.
v_Current_Node := Dbms_Xmldom.Item(v_Child_Nodes
,i);
Dbms_Xslprocessor.Valueof(v_Current_Node
,'@id'
,v_Id -- OUT
);
Dbms_Xslprocessor.Valueof(v_Current_Node
,'@companyName'
,v_Company_Name -- OUT
);
Dbms_Xslprocessor.Valueof(v_Current_Node
,'address/street/text()'
,v_Street -- OUT
);
Dbms_Xslprocessor.Valueof(v_Current_Node
,'address/city/text()'
,v_City -- OUT
);
-- Với trường hợp element có namespace
-- Cần phải thêm tham số thứ 4.
Dbms_Xslprocessor.Valueof(v_Current_Node
,'my-ns:note/text()'
,v_Note -- OUT
,'xmlns:my-ns=http://somedomain.com/abc');
Dbms_Output.Put_Line('v_Id=' || v_Id);
Dbms_Output.Put_Line('v_company_Name=' || v_Company_Name);
Dbms_Output.Put_Line(' - v_street=' || v_Street);
Dbms_Output.Put_Line(' - v_city=' || v_City);
Dbms_Output.Put_Line(' - v_Note=' || v_Note);
-- Lựa chọn các Node phù hợp với đường dẫn.
-- return Dbms_Xmldom.Domnodelist
v_Websites_Nodes := Dbms_Xslprocessor.Selectnodes(v_Current_Node
,'websites/website');
For j In 0 .. Dbms_Xmldom.Getlength(v_Websites_Nodes) - 1 Loop
v_Current_Node := Dbms_Xmldom.Item(v_Websites_Nodes
,j);
Dbms_Output.Put_Line(' - website=' ||
Dbms_Xslprocessor.Valueof(v_Current_Node
,'text()'));
End Loop;
End Loop;
Exception
When Others Then
Dbms_Output.Put_Line(Sqlerrm);
Dbms_Lob.Freetemporary(v_Xml_Clob);
Dbms_Xmlparser.Freeparser(p);
Dbms_Xmldom.Freedocument(v_Doc);
End;
Chạy ví dụ:

Nếu phần tử (element) của bạn có sử dụng namespace:<companies xmlns:my-ns="http://somedomain.com/abc"> <company id="111" companyName="Microsoft"> ..... <my-ns:note>Microsoft Note</my-ns:note> </company> .... </companies>
Bạn cần phải thêm tham số chỉ định namespace:Dbms_Xslprocessor.Valueof(v_Current_Node ,'my-ns:note/text()' ,v_Note -- OUT ,'xmlns:my-ns=http://somedomain.com/abc');
Ngược lại bạn sẽ nhận được lỗi:ORA-31011: XML parsing failed ORA-19202: Error occurred in XML processing LPX-00601: Invalid token in: 'my-ns:note/text()'