Để làm việc với dữ liệu XML ngoài cách sử dụng các truy vấn dạng XPath đã có trong một số ví dụ ở trên thì trong SQL server cho phép ta có thể thao tác và làm việc với các dữ liệu dạng XML thông qua cú pháp: OPENXML. Để thực hiện việc bóc tách dữ liệu từ một tài liệu XML ta đi tìm hiểu sâu hơn về cú pháp này. Trước tiên ta xem xét một ví dụ:
Ví dụ 17:
DECLARE @ABC XML
set @ABC = (SELECT CategoryID "Category/ID", CategoryName "Category/Name", Description "Category/Description"
FROM Categories WHERE CategoryID < 3
FOR XML Path('Categories'), TYPE)
SELECT @ABC.query('/Categories/Category')
Kết quả như sau:
<Category> <ID>1</ID>
<Name>Beverages</Name>
<Description>Soft drinks, coffees, teas, beers, and ales</Description>
</Category> <Category> <ID>2</ID>
<Name>Condiments</Name>
<Description>Sweet and savory sauces, relishes, spreads, and
seasonings</Description>
- 43 -
Trong ví dụ trên, tại bước 00 ta tạo bảng để lưu trữ dữ liệu đọc được từ tài liệu xml, sau đó khai báo một số biến, gán giá trị cho tài liệu xml. Cuối cùng sử dụng thủ tục sp_xml_preparedocument thủ tục này cho ta một đại diện để tham
Ví dụ 18:
-- Bước 00 --- ---
CREATE TABLE Customers (CustomerID varchar(20) primary key, ContactName varchar(20),
CompanyName varchar(20)) GO
CREATE TABLE Orders( CustomerID varchar(20), OrderDate datetime) GO
DECLARE @docHandle int
DECLARE @xmlDocument nvarchar(max) –- hoặc kiểu xml
SET @xmlDocument = N'<ROOT>
<Customers CustomerID="XYZAA" ContactName="Joe" CompanyName="Company1">
<Orders CustomerID="XYZAA" OrderDate="2000-08-25T00:00:00"/> <Orders CustomerID="XYZAA" OrderDate="2000-10-03T00:00:00"/> </Customers>
<Customers CustomerID="XYZBB" ContactName="Steve" CompanyName="Company2">No Orders yet!
</Customers> </ROOT>'
EXEC sp_xml_preparedocument @docHandle OUTPUT, @xmlDocument
-- Bước 01 --- ---
INSERT Customers SELECT *
FROM OPENXML(@docHandle, N'/ROOT/Customers') WITH Customers
-- Bước 02 --- ---
INSERT Orders SELECT *
FROM OPENXML(@docHandle, N'//Orders') WITH Orders
-- Bước 03 --- ---
SELECT * FROM OPENXML(@docHandle, N'/ROOT/Customers/Orders') WITH (CustomerID nchar(5) '../@CustomerID', OrderDate datetime)
-- Bước 04 --- ---
EXEC sp_xml_removedocument @docHandle
Kết quả như sau:
CustomerID OrderDate
1 XYZAA 2000-08-25 00:00:00.000 2 XYZAA 2000-10-03 00:00:00.000
- 44 -
chiếu đến tài liệu XML. Tại các bước 01, 02 ta sử dụng cú pháp OPENXML đểđọc dữ liệu từ tài liệu XML và lần lượt chèn dữ liệu đó vào trong các bảng Customers, Orders. Tại bước 03 ta sử dụng cú pháp OPENXML để đọc trực tiếp dữ liệu từ tài liệu XML và hiển thị. Tại bước 04 ta sử dụng thủ tục sp_xml_removedocument để xóa tài liệu XML ra khỏi bộ nhớ. Dưới đây là một thể hiện cho việc sử dụng cú pháp OPENXML.
(Hình 02. Hình mô tả phương thức làm việc với dữ liệu XML trong SQL Server)
Để hiểu rõ hơn về các làm việc với cú pháp OPENXML ta lần lượt đi tìm hiểu các thủ tục: sp_xml_preparedocument, sp_xml_removedocument và sau đó đi tìm hiểu chi tiết hơn cú pháp OPENXML.
Đầu tiên, ta tìm hiểu về thủ tục sp_xml_preparedocument
- 45 -
Đây là thủ tục là một trong 2 thủ tục mà SQL cung cấp để sử dụng kèm với cú pháp OPENXML để nạp tài liệu XML vào trong bộ nhớ trong của SQL sau đó tạo một tham chiếu đến tài liệu XML này. Chi tiết hơn:
- hdoc là kiểu số nguyên được trả ra ngay sau khi thực hiện thủ tục là giá trị để tham chiếu đến tài liệu trong biến xmltext và cũng là giá trị tham chiếu đến khi sử dụng cấu trúc OPENXML.
- xmltext là tài liệu XML ban đầu, tài liệu XML này sẽđược MSXML phân tích, giá trị đầu vào của xmltext có thể được định nghĩa bởi các kiểu dữ liệu sau: char, nchar, varchar, nvarchar, text, ntext, xml. Giá trị mặc định là NULL khi tài liệu đầu vào là rỗng.
- xpath_namespaces là những không gian tên được định nghĩa và được sử dụng trong các hàng, cột của cú pháp OPENXML thông qua các biểu thức XPath. xpath_namespaces là một tham số dạng text có kiểu là: char, nchar, varchar, nvarchar, text, ntext, xml. Giá trị mặc định của xpath_namespaces là: <root xmlns:mp="urn:schemas-microsoft-com:xml-metaprop">. Biểu thức này cung cấp các giá trị không gian tên URI cho các tiền tố được sử dụng trong các biểu thức XPath trong cú pháp OPENXML đối với các tài liệu XML chuẩn. xpath_ namespaces định nghĩa những tiền tố mà từ đó có thể tham chiếu đến không gian tên urn:schemas-microsoft-com:xml-metaprop, cung cấp phương thức để phân tích tài liệu XML. Tuy nhiên giá trị xpath_namespace vẫn có thể được bộ xử lý tài liệu XML hiểu được ngay cả khi nó là rỗng.
- Một điểm lưu ý là giá trị đầu vào của tài liệu XML trong xmltext có thể được định kiểu là văn bản hay là kiểu dữ liệu không phải là kiểu xml nhưng nó phải có thể chuyển đổi được từ các kiểu dữ liệu này sang thành kiểu dữ liệu xml.
Sau đây là một số ví dụ về các tài liệu XML được định nghĩa để sử dụng trong thủ tục sp_xml_preparedocument:
- 46 -
Dưới đây là tài liệu XML có: Đầu vào dạng varchar và namespace mặc định. Không gian tên mặc định được tự động tham chiếu đến khi gọi thủ tục
sp_xml_preparedocument:
Tài liệu XML dưới đây có: Đầu vào dạng varchar, namespace mặc định, và các hàm xác định tính hợp lệ của tài liệu nằm trong các DTD. Không gian tên mặc định được tựđộng tham chiếu đến khi gọi thủ tục sp_xml_preparedocument:
Tài liệu XML dưới đây có: Đầu vào dạng varchar, namespace được chỉđịnh. Khi gọi thủ tục sp_xml_preparedocument không gian tên urn:MyNamespace sẽ tự động được cập nhật vào:
Ví dụ 19:
DECLARE @hdoc int
DECLARE @doc varchar(1000) SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot"> <Order CustomerID="VINET" EmployeeID="5" OrderDate="1996-07- 04T00:00:00">
<OrderDetail OrderID="10248" ProductID="11" Quantity="12"/> <OrderDetail OrderID="10248" ProductID="42" Quantity="10"/> </Order>
</Customer> </ROOT>'
EXEC sp_xml_preparedocument @hdoc OUTPUT, @doc
Ví dụ 20:
DECLARE @hdoc int
DECLARE @doc varchar(2000) SET @doc = '
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE root
[<!ELEMENT root (Customers)*> <!ELEMENT Customers EMPTY>
<!ATTLIST Customers CustomerID CDATA #IMPLIED ContactName CDATA #IMPLIED>]>
<root>
<Customers CustomerID="ALFKI" ContactName="Maria Anders"/> </root>'
- 47 -
Tiếp theo, ta tìm hiểu về thủ tục sp_xml_removedocument:
Thủ tục này dù khi muốn loại bỏ đại diện của một tài liệu XML ra khỏi bộ nhớ của SQL. Khi ta gọi thủ tục sp_xml_preparedocument thì một đại diện của tài liệu XML được sinh ra và lưu vào trong bộ nhớ của SQL, khi ta muốn tương tác với tài liệu XML đó thì phải thông qua đại diện này, sau khi đã xử lý tài liệu XML đó xong ta có thể dùng thủ tục ở trên để xóa nó ra khỏi bộ nhớ để tránh cho việc tràn bộ nhớ của SQL.
Trong cú pháp trên, @docHandle được định nghĩa ở dạng số nguyên, là giá trị tham chiếu của tài liệu XML cần xóa ra khỏi bộ nhớ của SQL.
Tiếp theo, ta đi tìm hiểu cú pháp OPENXML để hiểu rõ cách để có thể phân tích một tài liệu XML.
OPENXML cung cấp cho ta một cái nhìn khác về tài liệu XML, trong cú pháp này ta có thể coi XML như một table hay view hoặc một OPENROWSET. Để sử dụng được cú pháp này ta đi tìm hiểu chi tiết các đối số trong cú pháp:
Ví dụ 21:
DECLARE @hdoc int
DECLARE @doc varchar(1000) SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot"> <Order CustomerID="VINET" EmployeeID="5"
OrderDate="1996-07-04T00:00:00">
<OrderDetail OrderID="10248" ProductID="11" Quantity="12"/> <OrderDetail OrderID="10248" ProductID="42" Quantity="10"/> </Order>
</Customer> </ROOT>'
EXEC sp_xml_preparedocument @hdoc OUTPUT, @doc, '<ROOT xmlns:xyz="urn:MyNamespace"/>'
EXEC sp_xml_removedocument @docHandle
OPENXML( iDocHandle int [in], rowpattern nvarchar [in], [ flags byte [in] ] )
- 48 -
- iDocHandle: là tham chiếu của tài liệu XML được sinh ra khi gọi thủ tục
sp_xml_preparedocument, đối số này được định nghĩa ở dạng số nguyên.
- rowpattern: là các cú pháp XPath dùng xác định các node (trong tài liệu XML được xử lý thông qua tham số iDocHandle) đểđược xử lý như các hàng.
- flags: chỉ ra cách thức để liên kết dữ liệu giữa tài liệu XML và bảng dữ liệu quan hệ. Cờ flags chỉ sự lựa chọn cho giá trị đầu vào và có thể nhận một trong các giá trị sau:
- SchemaDeclaration: là lược đồ định nghĩa có dạng như sau: ColName ColType [ColPattern | MetaProperty] [, ColNameColType [ColPattern | MetaProperty]...]
o ColName: Tên của cột dữ liệu trong bảng dữ liệu
STT Giá trị Mô tả
1. 0 Là giá trị mặc định, được hiểu là giá trị attribute-centric
2. 1 Có giá trị là: attribute-centric - kiểu tham chiếu dữ liệu, trong đó các phần tử có thuộc tính và lấy các thuộc tính làm trung tâm. Có thể được sử dụng kết hợp với XML_ELEMENTS, trong trường hợp này thuộc tính trung tâm được sử dụng đầu tiên và sau đó sẽ ánh xạ tới các cột mà chưa được xử lý.
3. 2 Có giá trị là: element-centric – kiểu tham chiếu dữ liệu, trong đó các phần tử được sử dụng làm trung tâm. Có thể được sử dụng kết hợp với XML_ATTRIBUTES, trong trường hợp này thuộc tính trung tâm được sử dụng đầu tiên và sau đó sẽ ánh xạ tới các cột mà chưa được xử lý.
4. 8 Có thể kết hoặc với XML_ELEMENTS hoặc với XML_ATTRIBUTES. Trong ngữ cảnh thu hồi, cờ này chỉ ra rằng dữ liệu sử dụng sẽ không được sao chép vào các thuộc tính @mp:xmltext.
- 49 -
o ColType: Là kiểu dữ liệu trong SQL server, nếu kiểu này khác với kiểu dữ liệu trong tài liệu XML thì sẽ bị chuyển về kiểu được định nghĩa.
o ColPattern: Là một lựa chọn, một mẫu XPath mô tả cách thức các node XML được tham chiếu đến. Nếu ColPattern không được chỉ định thì sẽ được tham chiếu mặc định( theo attribute-centric hoặc element-centric tùy theo cờ được xác định trong giá trị flags).
o MetaProperty: là một trong những metaproperty được cung cấp bởi OpenXML, nếu chỉ định MetaProperty thì các cột sẽ chứa các thông tin được cung cấp bởi MetaProperty này và sẽ cho phép ta trích xuất các thông tin ( chẳng hạn vị trí tương đối hay thông tin của không gian tên) của các XML node. Cho ta nhiều thông tin hơn trong văn bản đại diện.
- TableName: Là tên bảng được đưa ra thay vì SchemaDeclaration nếu một bảng với Schema mong muốn đã tồn tại hoặc không có cột mẫu yêu cầu.
- Chú ý: Trong cú pháp OPENXML để định dạng dữ liệu trả ra người ta sử dụng mệnh đề WITH, trong trường hợp không sử dụng mệnh đề WITH thì kết quả trả về cho ta là một bảng cạnh (edge table) có cấu trúc như sau:
Tên cột Kiểu dữ
liệu
Mô tả
Id bigint Là ID duy nhất của node dùng để định danh node. Phần tử ROOT có ID = 0
Parentid bigint Dùng xác định cha mẹ của node hiện tại, giá trị này không nhất thiết phải là phần tử cha của node, nó phụ thuộc vào kiểu của node để xác định. Chẳng hạn nếu kiểu của node là text thì cha của nó có thể là một thuộc tính. Nếu node ở cấp cao nhất thì cha của nó là NULL
Nodetype int Dùng xác định cha mẹ của node. Có các loại sau: - 1: Element Node
- 2: Attribute Node - 3: Text Node
localname nvarchar Cho biết tên của phần tử hoặc thuộc tính, nếu không có tên thì trả về NULL
- 50 -
prefix nvarchar Là tiền tố không gian tên của các tên node namespace
uri
nvarchar Là địa chỉ của không gian tên của node, có giá trị là NULL khi không có không gian tên.
datatype nvarchar Là kiểu dữ liệu thực tế của phần tử hay thuộc tính, nếu không thì sẽ là NULL. Kiểu dữ liệu này được suy ra từ các DTD hoặc Schema.
prev bigint Là ID của phần tử anh em trước đó, nhận giá trị NULL khi trước đó không có phần tử anh em nào.
text ntext Là giá trị của thuộc tính hay nội dung của phần tửở dạng văn bản. Có giá trị NULL nếu phần tử của bảng cạnh không yêu cầu giá trị.
Dưới đây là một số ví dụ sử dụng cú pháp OPENXML:
Sử dụng cú pháp OPENXML và so sánh dữ liệu khi sử dụng các cờ khác nhau. Khi flags = 1 giá trị được trả ra gồm 2 giá trị do lấy các thuộc tính CustomerID và ContactName làm trung tâm. Trong trường hợp flags = 2 do phần tử <Customer> không có phần tử con nên giá trị trả về là NULL, cụ thể:
- 51 -
Dưới đây là một ví dụ khác, trong đó có sử dụng các ColPattern để lấy ra giá trị của các thuộc tính và các phần tử con, mặc dù có chọn flags = 2 nhưng kết quả trả về vẫn lấy thông qua các liên kết của ColPattern:
Ví dụ 22:
DECLARE @idoc int
DECLARE @doc varchar(1000) SET @doc ='
<ROOT>
<Customer CustomerID="VINET" ContactName="Paul Henriot"> <Order CustomerID="VINET" EmployeeID="5" OrderDate="1996-07- 04T00:00:00">
<OrderDetail OrderID="10248" ProductID="11" Quantity="12"/> <OrderDetail OrderID="10248" ProductID="42" Quantity="10"/> </Order>
</Customer>
<Customer CustomerID="LILAS" ContactName="Carlos Gonzlez"> <Order CustomerID="LILAS" EmployeeID="3" OrderDate="1996-08- 16T00:00:00">
<OrderDetail OrderID="10283" ProductID="72" Quantity="3"/> </Order>
</Customer> </ROOT>'
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
---
SELECT *
FROM OPENXML (@idoc, '/ROOT/Customer',1)
WITH (CustomerID varchar(10), ContactName varchar(20)) EXEC sp_xml_removedocument @idoc
---
Sau đây là kết quả trả về:
|---| | CustomerID || ContactName | |---||---| | VINET || Paul Henriot | | LILAS || Carlos Gonzlez |
Trong trường hợp flags được chọn là 2:
|---| | CustomerID || ContactName | |---||---|