2.2.1. Giới thiệu
XQuery là ngôn ngữ mạnh đƣợc thiết kế để xử lý dữ liệu XML. Không chỉ tệp XML mà cả tệp dữ liệu có cấu trúc tƣơng tự XML: nested, named trees with attributes.
XQuery là ngôn ngữ truy vấn tài liệu XML, nó giống nhƣ ngôn ngữ truy vấn cơ sở dữ liệu quan hệ SQL. XQuery cho phép các nhà phát triển ứng dụng sử dụng các biểu thức để lấy dữ liệu ra từ các tài liệu XML. Dữ liệu đó có thể là một giá trị hoặc là cả một cấu trúc cây con của tài liệu, chẳng hạn là một thành phần với tất cả các thành phần con của nó.
XQuery sử dụng các biểu thức XPath, liên quan đến các từ khóa FLWOR nổi tiếng: for, let, where, order by, và return. Những từ khóa trên cung cấp phƣơng thức mạnh mẽ để tách và lấy dữ liệu từ tài liệu XML trong hầu hết các trƣờng hợp.
Cấu trúc ngữ pháp của ngôn ngữ XQuery đƣợc dựa trên cấu trúc cây của chính tài liệu XML. XQuery xử lý tốt cả các chỉ lệnh (instructions), thuộc tính (attribute) và các thành phần (element).
XQuery có thể đƣợc sử dụng nhằm mục đích lấy thông tin để sử dụng trong một dịch vụ Web, tạo các báo cáo tổng hợp, biến đổi dữ liệu XML thành XHTML hoặc tìm kiếm các tài liệu Web, từ đó cho ra các thông tin có liên quan dựa trên các cặp thẻ XML. XQuery cũng có thể đƣợc sử dụng để sản sinh ra các cấu trúc RDF hay truy xuất thông tin trên những nền tảng dựa trên XML. Vì bản thân các ngôn ngữ nhƣ RDF hay OWL cũng đƣợc biểu diễn thông qua XML nên chúng ta cũng có thể sử dụng XQuery để truy vấn thông tin trong các ontology đƣợc biểu diễn bởi RDF/OWL.
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
Các kiểu dữ liệu nguyên thủy:
o Numbers, gồm: integers, floating-point.
o boolean: true / false.
o Strings: ví dụ, "Hello world!". Không đƣợc modify một ký tự trong xâu.
o Các kiểu: dates, times, durations.
Một số kiểu XML-related. Ví dụ QName là cặp local name (ví dụ template) và một URL, để biểu diễn tag name, ví dụ xsl:template sau khi đã đƣợc phân giải tên.
Các kiẻu dẫn xuất là các biến thể, hạn chế thêm từ các kiểu nguyên thủy. các kiểu nguyên thủy + Các kiểu dẫn xuất -> atomic types. Nghĩa là các giá trị atomic không chứa những giá trị khác. String là atomic vì XQuery không có giá trị character.
Giá trị và biểu thức nút Node Values and Expressions
XQuery có kiểu dữ liệu nhận giá trị node để biểu diễn giá trị XML. Có 7 loại nút: element, attribute, namespace, text, comment, processing- instruction, và document (root) rất tƣơng tự với các lớp DOM, nhƣ Node, Element ... Một số cài đặt XQuery sử dụng các đối tƣợng DOM để cài đặt giá trị node.
Nhiều hàm chuẩn XQuery sẽ tạo ra hoặc trả về nodes. Hàm document
đọc một tệp XML và trả về document root node (the root element is a child of the root node).
Ta có thể tạo ra node mới ngay trong chƣơng trình. Tiện nhất là dùng một biểu thức tạo phần tử (element constructor expression), trông giống nhƣ dữ liệu XML thông thƣờng:
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
Có thể dùng dấu ngoặc nhọn {curly braces} để nhúng biểu thức XQuery trong biểu thức tạo phần tử
let $i := 2 return
let $r := <em>Value </em> return <p>{$r} of 10*{$i} is {10*$i}.</p> sẽ cho
<p><em>Value </em> of 10*2 is 20.</p>
Các bộ xử lý template nhƣ JSP, ASP, PHP, cho phép nhúng biểu thức của ngôn ngữ lập trình trong tệp HTML. XQuery cũng cho phép làm thế, hơn nữa, có thể nhúng các forms XML/HTML bên trong biểu thức, là giá trị của biến hay tham số. Giá trị node trong XQuery là immutable, không thể sửa đổi sau khi đã tạo xong.
2.2.2. Biểu thức đƣờng dẫn trong Xquery và quan hệ với XPath.
XQuery vay mƣợn các biểu thức đƣờng dẫn (path expressions) từ XPath. XQuery có thể coi là tổng quát hóa của XPath. Trừ vài ngoại lệ, mọi biểu thức XPath là biểu thức XQuery.
XML xác định các nút thông qua các đƣờng dẫn tới các nút đó, với "đầu đƣờng" là phần tử gốc (root element), tiếp theo là các phần tử ...kỵ, cụ, ông, cha, và kết thúc là nút cần truy xuất.
Các biểu thức đƣờng dẫn đƣợc sử dụng để định vị các nút và ràng buộc biếnđổi. Giả sử có tệp XML "mybook.xml" với phần tử gốc là <book>, chứa một số phần tử con là <chapter>:
let $book := document("mybook.xml")/book return $book/chapter
Hàm document trả về nút root. Biểu thức /book trả về phần tử con của root, tên là book. Vậy $book là phần tử root duy nhất.
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
$book/chapter sẽ trả về sequence các nút chapter (mức 2) theo trình tự có trong tài liệu (document order).
Ví dụ sau chứa predicate:
$book//para[@class="warning"]
Chỉ chọn các nút hậu thế <para> mà có nút thuộc tính tên là class và nhận giá trị "warning"
Sự khác nhau: biểu thức XPath trả về node set, cũng chính biểu thức XQuery đó trả về dãy nút. theo trình tự document order và loại bỏ duplicates - > tƣơng đƣơng với sets.
XSLT rất hữu ích cho các transformations rất đơn giản, nhƣng các stylesheets phức tạp hơn (nhất là chứa logic or programming không tầm thƣờng) sẽ đƣợc viết ngắn gọn hơn bằng XQuery.
2.2.3. Lặp theo Sequences.
Biểu thức for cho phép lặp theo các phần tử của một sequence: for $x in (1 to 3) return ($x,10+$x)
evaluates thành dãy 6-phần tử: 1,11,2,12,3,13.
Dƣới đây là một ví dụ hữu ích hơn, tạo ta một trang gồm các tên chƣơng của một cuốn sách.
<html>{
let $book := document("mybook.xml")/book for $ch in $book/chapter
return <h2>{$ch/title)</h2> }</html>
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
2.2.4. Các hàm trong Xquery.
XQuery cung cấp hơn 100 hàm dựng sẵn,các hàm các giá trị chuỗi, số, so sánh ngày và tháng…Ngoài ra Xquery còn có các hàm do ngƣời dùng tự định nghĩa, cú pháp:
declare function prefix:function_name($parameter AS datatype) AS
returnDatatype {
(:...function code here... };
XQuery cho phép ngƣời sử dụng định nghĩa các hàm. Trong phần query
prologue của một chƣơng trình XQuery. Chú ý rằng các tham số, kết quả … của hàm có thể là giá trị nguyên thủy, nodes, hay sequences của chúng.
hàm đệ quy sau đây trả về mọi nút hậu thế của một nút (depth-first traversal)
define function descendant-or-self ($x) { $x, for $y in children($x) return descendant-or-self($y) } descendant-or-self(<a>X<b>Y</b></a>) evaluates thành sequence độ dài 4:
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
2.2.5. Sắp xếp và Context.
Biểu thứcsortby . Sắp xếp dãy books theo tên tác giả: $books sortby (author/name)
Đầu vào của sortby là một sequence ($books) và một biểu thức để sắp thứ tự ordering expressions. Lấy 2 giá trị từ sequence đầu vào, tính giá trị của
ordering expression trong bối cảnh tƣơng ứng, so sánh với nhau để xác định cái nào đứng trƣớc.
Ví dụ trên: biểu thức author/name sẽ đƣợc tính nhiều lần, ứng với từng book khác nhau, là context (or current) item.
Biểu thức đƣờng dẫn cũng sử dụng và thiết lập context. Trong biểu thức author/name,phần tử con name đƣợc trả về là name ở trong context item, tức là author item.
2.2.6. Đặc tả kiểu
XQuery là ngôn ngữ định kiểu mạnh. Giống nhƣ Java và C#. Nó hỗn hợp cả static typing và dynamic typing (kiểm tra nhất quán về kiểu khi biên dịch và run-time). Tuy nhiên, các kiểu trong XQuery khác các lớp trong OO. Nó khớp với mô hình dữ liệu XQuery và cho phép nhập khẩu các kiểu từ lƣợc đồ XML.
if ($child instance of element section) then process-section($child)
else ( ) {--nothing--}
Mã lệnh trên sẽ gọi hàm process-section nếu giá trị của $child là một phần tử có tên thẻ là section.
XQuery áp dụng lệnh viết tắt typeswitch để so khớp một giá trị với một số kiểu. Ví dụ dƣới đây sẽ đổi tên thẻ <para> thành <p> và <emph> thành <em>.
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
typeswitch ($x)
case element para return <p>{process-children($x)}</p> case element emph return <em>{process-children($x)}</em> default return process-children($x)
}
define function process-children($x) { for $ch in children($x) return convert($ch) }
2.2.7. Các biểu thức FLWOR
Một trong những tiện ích mạnh mẽ nhất của ngôn ngữ truy vấn XQuery là các biểu thức FLWOR (For, Let, Where, Order by, Return). Biểu thức này tƣơng tự nhƣ cấu trúc SELECT - FROM - WHERE của SQL về nhiều mặt. Chúng có thể đƣợc dùng để kết nối dữ liệu tới các biến, duyệt qua danh sách, lọc, trình diễn, tái cấu trúc các biến…
Các mệnh đề For và Let đƣợc sử dụng để nối kết các biến tới các dữ liệu trung gian; nối kết giữa hai tài liệu, hay hai dãy của các phần tử (item) hoặc sinh ra các luồng dữ liệu.
Mệnh đề Where đƣợc sử dụng trong các biểu thức FLWOR để lọc các luồng dữ liệu theo những giới hạn trong các biến của các mệnh đề for và let. Ví dụ:
for $b in doc("books.xml")//book where $b/@year = "2000"
return $b/title
Kết quả trả về là các phần tử tiêu đề nhƣ: <title>Data on the Web</title> Mệnh đề Order by đƣợc sử dụng để chỉ định thứ tự các kết quả đƣợc trả về bởi mệnh đề where sẽ đƣợc xử lý bởi mệnh đề return.
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
Mệnh đề Return: Sau khi mệnh đề Order by đƣợc sử dụng để sắp xếp kết quả, các kết quả này đƣợc chuyển sang mệnh đề return, đƣợc đánh giá lại một lần nữa và trả về cho ngƣời dùng.
L là LET
Mệnh đề XQuery let đơn giản chỉ là khai báo biến và gán trị: let $maxCredit := 3000
let $overdrawnCustomers := //customer[overdraft > $maxCredit] return count($overdrawnCustomers)
Ý nghĩa là rõ ràng. Thay thế tên biến bằng biểu thức đƣợc gán: count(//customer[overdraft > 3000])
Trong mệnh đề for, biến đƣợc buộc lần lƣợt với từng mục trong dãy. Trong mệnh đề let, biến chỉ nhận một giá trị. Có thể là một mục hay một dãy mục (XQuery không phân biệt, một mục đƣợc coi là một dãy có độ dài 1). Dĩ nhiên dãy có thể chứa các nút, các giá trị nguyên tử hoặc hỗn hợp cả hai (nếu bạn muốn).
Trong nhiều trƣờng hợp, khai báo biến chỉ để cho thuận tiện, làm đơn giản cách viết biểu thức. Nếu bạn dùng một biểu thức hơn một lần thì khai báo biến là cách làm tốt để bộ xử lsy chỉ cần tính một lần.
Trong biểu thức FLWOR, có thể có nhiều mệnh đề for, nhiều mệnh đề
let, và trình tự tùy ý. Ví dụ: for $genre in //genre/choice
let $genreVideos := //video[genre = $genre] let $genreActorRefs := $genreVideos/actorRef for $actor in //actor[@id = $genreActorRefs] return concat($genre, ": ", $actor)
Đây là lời dịch nghĩa ra ngôn ngữ hàng ngày: Và đây là kết quả truy vấn:
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
Stylus Studio có một công cụ trợ giúp nhanh là XQuery mapper, cho phép xem trực quan map từ một hay nhiều tài liệu XML đầu vào tới khuôn dạng đích bất kỳ.
Khối FLWOR đƣợc biểu diễn đồ họa dƣới dạng một khối chức năng, có 3 cổng vào ở bên trái (For, Where, Order By), một cổng điều khiển luồng ở
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
trên đỉnh, và một cổng ra ở bên phải. Khi bạn vẽ các ánh xạ XML, hệ thống sinh mã XQuery cho bạn. ngƣợc lại, khi bạn viết mã XQuery, biểu diễn đồ họa cũng đƣợc cập nhật theo.
Sử dụng biến trong XQuery
Một điều lý thú là có thể dùng hoặc let hoặc for nếu biến chỉ nhận một giá trị riêng lẻ: let $x := 3 return $x*x hoàn toàn tƣơng đƣơng với for $x in 3 return $x * $x. Có nhiều mẹo khi dùng XPath 2.0 hơn là dùng XQuery, vì XPath cung cấp biểu thức FLWOR rút ngắn, chỉ còn 2 mệnh đề for và return.
Một điểm quan trọng cần nhớ về các biến trong XQuery (cũng giống trong XSLT) Các biến không cập nhật được. Nghĩa là không thể viết let $x := $x+1. Quy tắc này có vẻ lạ nếu bạn hy vọng XQuery hành động nhƣ một ngôn ngữ lập trình procedural, kiểu nhƣ JavaScript. Nhƣng XQuery là ngôn ngữ declarative và làm việc ở mức cao. Không có quy tắc về trình tự thi hành các biểu thức, các cấu kiện mà kết quả phụ thuộc trình tự thi hành (like variable assignment) sẽ bị cấm. Ràng buộc này đảm bảo cho bộ tối ƣu hóa tìm đƣợc chiến lƣợc tìm kiến CSDL lớn trong thời gian ngắn.
Trong biểu thức dƣới đây có cập nhật biến hay không ? for $v in //video
let $x := xs:int($v/runtime) * xdt:dayTimeDuration("PT1M") return concat($v/title, ": ",
hours-from-duration($x), " hour(s) ", minutes-from-duration($x), " minutes")
(Truy vấn sẽ hiển thị thời gian chạy của mỗi video. Đầu tiên nó chuyển đổi giá trị từ dạng string thành một số nguyên, sau đó nhân với một phút (PT1M) để nhận đƣợc thời gian chạy).
Ở đây biến $x nhận các giá trị khác nhau trong mỗi vòng lặp for. Tuy nhiên, về kỹ thuật, mỗi vòng lặp sẽ khởi tạo biến mới chứ không phải gán trị
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
mới cho biến cũ. Bạn không thể cộng tích lũy các biến đƣợc. Hãy thử truy vấn sau:
let $totalDuration := 0 for $v in //video
let $totalDuration := $totalDuration + $v/runtime return $totalDuration
Kết quả không phải là tổng số mà là một dãy các thời gian chạy ứng với từng video. Ví dụ này khai báo 2 biến $totalDuration khác nhau có cùng tên. Rõ hơn sẽ là:
let $zero := 0 for $v in //video
let $totalDuration := $zero + $v/runtime return $totalDuration
và là tƣơng đƣơng với: for $v in //video
return 0 + $v/runtime
Bây giờ thì dễ hiểu tại sao lại trả về một dãy chứ không phải là tổng số. Cách làm đúng là dùng hàm sum : sum(//video/runtime)
W là WHERE
Mệnh đề where trong biểu thức FLWOR có chức năng rất giống với mệnh đề WHERE trong SQL: nó chỉ rõ điều kiện lọc ra các mục đƣợc quan
tâm. Mệnh đề where trong biểu thức FLWOR là tùy chọn, nhƣng nếu có mặt
thì chỉ duy nhất một lần, sau các mệnh đề for và let. Dƣới đây viết lại các truy vấn trên, có dùng mệnh đề where:
for $genre in //genre/choice for $video in //video
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
for $actor in //actor
where $video/genre = $genre and $actor/@id = $actorRefs return concat($genre, ": ", $actor)
Ngƣời quen dùng SQL có xu hƣớng viết truy vấn kiểu này: đầu tiên xác định tất cả các bảng cần đến, sau đó định nghĩa biểu thức WHERE thể hiện các ràng buộc để chọn lọc một tập con các hàng trong bảng và điều kiện join để nối các bảng.
Tự nhiên hơn là thực hiện các điều kiện lọc trong một vị từ (predicate) gắn với mệnh đề for, nhƣ sau:
for $genre in //genre/choice
for $video in //video[genre = $genre] for $actorRefs in $video/actorRef for $actor in //actor[@id = $actorRefs] return concat($genre, ": ", $actor)
Hãy nhớ rằng trong một predicate, chọn mục và kiểm tra điều kiện tƣơng đối so với nút bối cảnh. Còn trong mệnh đề where, bạn chọn bằng một tên biến. Chỉ trần trụi tên biến đƣợc chọn ./child::genre - tức là chọn phần tử con của nút bối cảnh, ở đây là nút <video>. Thƣờng dùng biểu thức kiểu này trong predicates, và rất ít khi dùng nó trong mệnh đề where. Và nếu dùng một bộ xử lý chema-aware (sẽ trình bày trong bài viết khác) thì có thể nhận đƣợc thông báo lỗi (nếu dùng mệnh đề where). Lúc này kết quả sẽ là điều kiện where đƣợc tính là false, không đƣợc thỏa mãn và không chọn ra cái gì cả. Bạn sẽ mất thì giờ giải đáp câu đố, tại sao tập kết quả là rỗng.
O là ORDER BY
Nếu không có mệnh đề order by trong biểu thức FLWOR thì trình tự các kết quả sẽ theo trình tự mà mệnh đề for định nghĩa trong các vòng lặp bên
Số hóa bởi Trung tâm Học liệu – Đại học Thái Nguyên http://www.lrc-tnu.edu.vn
trong. Đây là điểm khác biệt quan trọng so với SQL, ở đó trình tự kết quả là