11/23/11

XQuery mở rộng XPath như thế nào

Tóm tắt:  XPath và XQuery giống nhau về một số mặt. Thậm chí XPath là một phần trọn vẹn của XQuery. Cả hai ngôn ngữ cho phép bạn chọn những mẩu dữ liệu từ một tài liệu XML hoặc một kho lưu trữ tài liệu XML. Trong bài viết này, bạn sẽ tìm thấy các mô tả về XPath và XQuery, và tìm hiểu xem XQuery mở rộng XPath như thế nào.
Mặc dù cả XPath lẫn XQuery thực hiện một số chức năng giống nhau, XPath mang lại sự đơn giản còn XQuery cung cấp thêm sức mạnh và tính linh hoạt. XPath là công cụ hoàn hảo cho nhiều kiểu truy vấn. Ví dụ, XPath là cách dễ nhất để bạn tạo một danh sách không sắp thứ tự các số điện thoại từ một tập hợp con các bản ghi trong một tài liệu XML. Tuy nhiên, nếu bạn cần một truy vấn biểu diễn các tiêu chuẩn lựa chọn bản ghi phức tạp hơn, có chuyển đổi tập kết quả, hoặc yêu cầu đệ quy, thì bạn cần XQuery.


XPath

XPath là một ngôn ngữ đặc thù của một lĩnh vực (DSL - domain-specific language) nhưng nhanh chóng trở thành một phần quan trọng của các ngôn ngữ mục đích chung khác. Các ngôn ngữ lập trình tích hợp XPath thông qua các mô đun và các lớp, và trong một số trường hợp kết hợp trực tiếp vào trong cú pháp của các ngôn ngữ ấy. Điều này cũng tương tự như những gì đã xảy ra với các biểu thức chính quy trước đây ít lâu.

XPath là phổ biến vì ngôn ngữ này có thể tiết kiệm đáng kể thời gian và nỗ lực cho nhà phát triển khi trích xuất những mẩu dữ liệu cụ thể từ một tài liệu XML. Ngay cả những người chưa bao giờ làm việc với XPath trước đó cũng có thể nhanh chóng khai thác sức mạnh của nó. Hãy xem xét đoạn mã XML trong Liệt kê 1.

Liệt kê 1. Tài liệu XML
View Code:
  <users>
    <user>
      <name>
        <first>Lola</first>
        <last>Solis</last>
      </name>
      <age>2</age>
    </user>
    <user>
      <name>
        <first>Nina</first>
        <last>Serafina</last>
      </name>
      <age>4</age>
      <visits>
        <first>2008-01-15</first>
        <last>2008-02-15</last>
      </visits>
    </user>
    <user>
      <name>
        <first>Tracy</first>
        <last>Keller</last>
      </name>
      <age>35</age>
    </user>
  </users>


Nếu bạn muốn thu được một danh sách các tên họ của trẻ em trong tài liệu này, bạn có thể sử dụng biểu thức XPath sau.

Liệt kê 2. Chọn các tên họ của người dùng dưới 18 tuổi

View Code:
  /user[age lt 18]/name/last/text()

  (: Result
       Solis
       Serafina
  :)


Hãy tưởng tượng mã bạn phải viết để trích xuất dữ liệu nếu không dùng XPath. Ngay cả với sự trợ giúp của các biểu thức chính quy, bạn cần phải suy nghĩ một chút về cách làm thế nào để loại trừ giá trị của thẻ cuối cùng trong nút visits.

Biểu thức XPath nói trên không chỉ ngắn gọn, mà còn khá rõ ràng. Nhìn thoáng qua cũng có thể phát hiện ra biểu thức đang làm gì, ngay cả với những người không biết XPath. XPath được dùng vì nó mạnh mẽ và vì nó có một lịch sử lâu đời đằng sau. Ngôn ngữ này hiểu các nút trong một tài liệu XML phức tạp tùy ý, và quan trọng hơn, còn biết các mối quan hệ giữa các nút đó. Vì vậy, bạn có thể viết các biểu thức ngắn gọn không chỉ xem xét các phần tử và các giá trị phần tử, mà còn xem xét cả các thuộc tính, các lệnh xử lý, và v.v..

Nhiều truy vấn XML rất khó biểu diễn một cách rõ ràng hơn và ngắn gọn hơn so với XPath. Tuy nhiên, bản chất đặc thù cho một lĩnh vực của XPath và các mục tiêu của ngôn ngữ này buộc các nhà lập trình phải chấp nhận một số hạn chế khá quan trọng. Các phần sau đây mô tả ngắn gọn ngôn ngữ XQuery và cho thấy các vấn đề mà chỉ riêng XPath không thể giải quyết được. Những vấn đề này đòi hỏi các nhà lập trình vượt ra khỏi Xpath, cần đến một công cụ như XQuery.
XQuery

Do XQuery hỗ trợ XPath một cách tự nhiên, như là một phần của cú pháp XQuery, nên XQuery rõ ràng có thể làm tất cả mọi thứ mà XPath có thể làm được. Nhưng XQuery là hoàn toàn Turing và có thể được coi như một ngôn ngữ mục đích chung; nên nó dễ dàng vượt qua nhiều hạn chế của XPath, nhưng phải trả giá bằng thêm một chút phức tạp.

Tổng quan

XQuery sử dụng một cú pháp đơn giản, là sự pha trộn của XML, XPath, các chú thích, các hàm, và một cú pháp biểu thức đặc biệt để liên kết tất cả lại với nhau. Mã XQuery hoàn toàn là các biểu thức, không có câu lệnh nào. Tất cả các giá trị là các dãy và tính đơn giản là quan trọng đối với ngôn ngữ này. Vì vậy, cả hai biểu thức Hi và 2 * 2 là mã XQuery hợp lệ và sẽ chạy thi hành mà không cần bất kỳ chuẩn bị dạo đầu hay sửa đổi nào. XQuery là một ngôn ngữ mức cao, định kiểu mạnh, dùng hàm (không có các hiệu ứng phụ) là lý tưởng để biểu thị một truy vấn nhằm nhận được dữ liệu cả từ một tài liệu XML lẫn từ một kho lưu trữ tài liệu XML lớn. Về khía cạnh thứ hai này, nó khá giống như SQL. Nhưng XQuery cung cấp thêm khả năng để biểu diễn một phép chuyển đổi tùy ý với tập kết quả. Cũng giống như sử dụng XPath sẽ có lợi khi bạn muốn lấy ra một số dữ liệu từ một tài liệu XML, việc sử dụng XQuery cũng khá lợi ích khi bạn muốn lấy ra và chuyển đổi dữ liệu từ một kho lưu trữ lớn các tài liệu XML.

Chuyển đổi tập kết quả

Một hạn chế rõ ràng của XPath là nó không cung cấp việc chuyển đổi tập kết quả theo bất kỳ cách nào. Giả sử bạn muốn trả về các kết quả từ các truy vấn XPath ở trên (Liệt kê 2) sắp theo thứ tự chữ cái, như được hiển thị trong Liệt kê 3.

Liệt kê 3. Các kết quả theo thứ tự chữ cái
View Code:

Serafina
Solis


Bạn không thể làm điều này với XPath. Để đạt được điều này, bạn sẽ phải viết mã bằng ngôn ngữ khác (ví dụ, như XQuery) hoặc sử dụng một số phần mở rộng XPath đặc biệt, độc quyền để sắp xếp các kết quả.

Trái lại, XQuery cho phép bạn sắp xếp các kết quả hoặc chuyển đổi chúng thành HTML, CSV, SQL, hoặc bất kỳ định dạng dựa trên văn bản khác nào. Trong số các kiểu các chuyển đổi mạnh mẽ nhất mà bạn có thể làm với XQuery là các chuyển đổi XML thành XML. Thông thường các cơ sở dữ liệu XML lớn có thể chứa rất nhiều các tài liệu XML phức tạp, có tương quan với nhau, mà một ứng dụng khách không cần. XQuery cho phép một ứng dụng khách mô tả chính xác kiểu tài liệu XML mà nó muốn được máy chủ trả về. Nhờ cung cấp một giao diện XQuery, nên một máy chủ thường có thể tránh được việc lưu trữ dữ liệu theo nhiều lược đồ. Hơn nữa, việc sử dụng XQuery để chuyển đổi dữ liệu cho một ứng dụng khách thường dễ dàng hơn và nhanh hơn so với cố gắng chuyển đổi dữ liệu bằng Perl hoặc Java hoặc bằng một số ngôn ngữ máy tính phổ biến khác. Chắc chắn, việc chuyển đổi dữ liệu bằng XQuery khi bạn lấy ra dữ liệu trong lúc đang triển khai sẽ nhanh hơn nhiều so với việc thực hiện một chuyển đổi sau đó bằng XSLT.

Để liên kết các tiêu chí chọn bản ghi và các lệnh chuyển đổi tập kết quả với nhau, XQuery cung cấp một tính năng gọi là biểu thức FLWOR (phát âm giống từ "flower"). Các chữ cái trong từ này là viết tắt của các từ for, let, where, order by và return. Đây là những phần tử có thể tạo ra một biểu thức FLWOR. Biểu thức FLWOR có chứa ít nhất một vài trong số các phần tử ấy theo trình tự đại thể giống như từ viết tắt đã gợi ý. Tất cả các biểu thức FLWOR bắt đầu bằng một biểu thức for hoặc let và kết thúc bằng một biểu thức return (trả về). Nếu bạn đã quen thuộc với SQL, thì có lẽ bạn đã thấy tôi đã xử lý biểu thức này ở đâu rồi. Dưới đây là một biểu thức FLWOR đơn giản, mượn từ bài thơ "Outwitted" của Edwin Markham (xem Liệt kê 4).

Liệt kê 4. Biểu thức FLWOR đơn giản

View Code:

let $xml:=
  <a>
    <one>She drew a circle that shut me out</one>
    <two>Heretic rebel, a thing to flout</two>
  </a>

return $xml//one/text()

(: Result
    "She drew a circle that shut me out"
:)


Liệt kê 5 cho thấy cách bạn có thể áp dụng một biểu thức FLWOR đơn giản với XML trong Liệt kê 1. (Để ngắn gọn, liệt kê này chỉ viết _XML from Listing 1_ thay cho toàn bộ XML thực tế ở chỗ đó).

Liệt kê 5. Biểu thức FLWOR đơn giản

View Code:
let $xml:= _XML from Listing 1_
for $user in $xml//user[age lt 18]
order by $user/name/last
return $user/name/last/text()

(: Result
    Serafina
    Solis
:)


Nếu bạn muốn truy vấn để trả về một đoạn HTML biểu thị kết quả như là một danh sách có đánh số, thì bạn có thể áp dụng XQuery từ Liệt kê 6.

Liệt kê 6. Biểu thức FLWOR đơn giản xuất ra một danh sách có đánh số trong HTML
View Code:

let $xml:= _XML from Listing 1_
return
  <ol>{
    for $user in $xml//user[age lt 18]
    order by $user/name/last
    return <li>{$user/name/last/text()}</li>
  }</ol>

(: Result
    <ol><li>Serafina</li><li>Solis</li></ol>
:)


Lưu ý cách XML và XQuery pha trộn rất trực giác và hiệu quả trong Liệt kê 6.
Diễn tả các tiêu chí chọn bản ghi phức tạp hơn

Ngoài việc chuyển đổi dữ liệu mà nó lấy ra, điểm đầu tiên phải nói là XQuery cũng tốt hơn nhiều so với XPath về tìm kiếm dữ liệu. XQuery và XPath thường có các dư thừa, có thể giúp các nhà lập trình diễn tả tốt hơn các truy vấn. Ví dụ, Liệt kê 7 cho thấy bạn có thể di chuyển đoạn biểu thức XPath age lt 18 vào một mệnh đề where trong biểu thức FLWOR như thế nào.

Liệt kê 7. Diễn tả các ràng buộc XPath bằng XQuery

View Code:
let $xml:= _XML from Listing 1_
return
  <ol>{
    for $user in $xml//user
    where $user/age lt 18
    order by $user/name/last
    return <li>{$user/name/last/text()}</li>
  }</ol>



Kết quả mà biểu thức trong Liệt kê 7 tạo ra là hoàn toàn giống như kết quả của biểu thức trong Liệt kê 6. Tuy nhiên, mệnh đề where của XQuery là linh hoạt hơn đáng kể so với cú pháp XPath để diễn tả các ràng buộc. Mệnh đề where của XQuery có thể chứa các biểu thức lồng nhau phức tạp tùy ý mà thậm chí có thể bao gồm các cuộc gọi hàm. XQuery không áp đặt các hạn chế đối với các biểu thức chọn bản ghi.

Sử dụng các hàm và đệ quy

Trong khi XPath không hỗ trợ các hàm, thì XQuery lại cung cấp một sưu tập có giá trị gồm các hàm và các phép toán dựng sẵn và cũng cho phép những người dùng định nghĩa các hàm riêng của mình. Các hàm XQuery được định kiểu mạnh, hỗ trợ đệ quy, và có thể được khai báo là bên trong hay bên ngoài. Hàm bên trong là một hàm chuẩn ở đây phần thân của hàm tiếp sau phần khai báo hàm. Hàm bên ngoài là một kiểu khai báo hàm để mở ra cánh cửa cho các việc triển khai thực hiện nhằm cho phép người dùng định nghĩa phần thân của hàm bằng một ngôn ngữ lập trình khác.

Trong khi đệ quy có thể không phải là cách tiếp cận tốt nhất để giải quyết các nhiệm vụ mà nhiều nhà phát triển thực hiện hàng ngày, nó thường tỏ ra tiện dụng khi bạn làm việc với XML, có thể chứa các nút lồng nhau tùy ý. Hãy xem xét hàm transform-names được định nghĩa trong Liệt kê 8.

Liệt kê 8. Hàm đơn giản để thay đổi các tên nút trong bất kỳ tài liệu XML nào
View Code:

(: Part 1 :)
define function transform-names($node as node()) as node() {
  element{replace(name($node), "_", "-")} {
    $node/text(), for $subnode in $node/* return transform-names($subnode)
  }
}

(: Part 2 :)
let $xml:=
<item>
  <item_type>book</item_type>
  <contributors>
    <author>
      <first_name>Charles</first_name>
      <last_name>Edward</last_name>
      <home_address>
        <home_street>206 S. Solomon St.</home_street>
        <home_city>New Orleans</home_city>
        <home_state>LA</home_state>
        <home_zip>70119</home_zip>
      </home_address>
    </author>
    <artist>
      <last_name>Salinas</last_name>
    </artist>
  </contributors>
</item>
return transform-names($xml)

(: Result
    <item>
      <item-type>book</item-type>
      <contributors>
        <author>
          <first-name>Charles</first-name>
          <last-name>Edward</last-name>
          <home-address>
            <home-street>206 S. Solomon St.</home-street>
            <home-city>New Orleans</home-city>
            <home-state>LA</home-state>
            <home-zip>70119</home-zip>
          </home-address>
        </author>
        <artist>
          <last-name>Salinas</last-name>
        </artist>
      </contributors>
    </item>
:)


Hàm transform-names này, chỉ đơn thuần là đoạn mã xuất hiện trong Phần 1 của Liệt kê 8, nhận đầu vào là một tài liệu XML hoặc nút XML phức tạp tùy ý. Trong tất cả các tên thẻ XML, hàm này thay thế bất kỳ ký tự gạch dưới (_) nào bằng một dấu gạch ngang (-).

Đệ quy trong trường hợp này làm cho việc duyệt qua toàn bộ cấu trúc của tài liệu XML trở thành tầm thường. Kết quả là, hàm này rất ngắn (chỉ có 3 dòng!), dễ duy trì, và làm việc được với bất kỳ tài liệu hoặc nút XML hợp lệ nào không sử dụng các thuộc tính. Ngay cả khi việc nắm vững hoàn toàn hàm này ngay từ đầu có vẻ có một chút khó khăn — đặc biệt là đối với các nhà lập trình không thường xuyên sử dụng đệ quy — người ta vẫn có thể nhanh chóng đoán ra cách sửa đổi hàm này để xóa các dấu gạch dưới thay vì thay thế chúng bằng dấu gạch ngang.

Diễn tả các phép nối

XPath không cung cấp một phương tiện để nối các nút XML trong một truy vấn. Tuy nhiên, giống như SQL cung cấp một cú pháp tự nhiên để diễn tả các phép nối bảng trong các truy vấn, XQuery cung cấp một cách trực quan (ít nhất với người dùng SQL) để nối các tập các nút XML. Mã trong Liệt kê 9 mô tả các phép nối làm việc trong XQuery như thế nào.

Liệt kê 9. Biểu thức nối của XQuery

View Code:
(: Part 1 :)
let $authors:=
  <authors>
    <author>
      <name>Harold Abelson</name>
      <books>
        <isbn>978-0-07-000422-1</isbn>
        <isbn>978-0-262-01063-4</isbn>
      </books>
    </author>
    <author>
      <name>Paul Graham</name>
      <books>
        <isbn>978-0-13-370875-2</isbn>
        <isbn>978-0-13-030552-7</isbn>
        <isbn>978-0-596-00662-4</isbn>
      </books>
    </author>
    <author>
      <name>Apostolos-Paul Refenes</name>
      <books>
        <isbn>978-0-471-94364-8</isbn>
        <isbn>978-981-02-2819-4</isbn>
      </books>
    </author>
  </authors>

(: Part 2 :)
let $books:=
  <books>
    <book>
      <title>Structure and Interpretation of Computer Programs</title>
      <isbn>978-0-07-000422-1</isbn>
    </book>
    <book>
      <title>Turtle Geometry</title>
      <isbn>978-0-262-01063-4</isbn>
    </book>
    <book>
      <title>ANSI Common LISP</title>
      <isbn>978-0-13-370875-2</isbn>
    </book>
    <book>
      <title>On LISP</title>
      <isbn>978-0-13-030552-7</isbn>
    </book>
    <book>
      <title>Hackers and Painters</title>
      <isbn>978-0-596-00662-4</isbn>
    </book>
    <book>
      <title>Neural Networks in the Capital Markets</title>
      <isbn>978-0-471-94364-8</isbn>
    </book>
    <book>
      <title>Neural Networks in Financial Engineering</title>
      <isbn>978-981-02-2819-4</isbn>
    </book>
    <book>
      <title>Handbook of Artificial Intelligence</title>
      <isbn>978-0-201-16889-1</isbn>
    </book>
    <book>
      <title>Artificial Intelligence Programming</title>
      <isbn>978-0-89859-609-0</isbn>
    </book>
    <book>
      <title>A New Guide to Artificial Intelligence</title>
      <isbn>978-0-89391-607-7</isbn>
    </book>
    <book>
      <title>Artificial Intelligence</title>
      <isbn>978-0-08-034112-5</isbn>
    </book>
    <book>
      <title>Artificial Intelligence</title>
      <isbn>978-0-631-18385-3</isbn>
    </book>
  </books>

(: Part 3 :)
return
  <books-complete-info>{
    for $book in $books/*
      for $author in $authors/*
        where $book/isbn = $author//isbn
          and (
            contains($book/title, "LISP")
            or contains($book/title, "Neural"))
    order by $book/title    
    return <book>{$book/*, $author/name}</book>
  }</books-complete-info>


Phần 1 và 2 của Liệt kê 9 gán các tài liệu XML cho các biến authors (các tác giả) và books (các sách). Một số các nút trong books liên quan đến các nút trong authors, như vậy một nút book có một ISBN, là một trong số các IBSN được liệt kê cho một nút author (tác giả).

Phần 3 của liệt kê này có chứa một biểu thức nối XQuery để tập hợp một tài liệu XML mới, books-complete-info (xem phần trước trong Liệt kê 10), có chứa các nút book bao gồm tên của tác giả.

Lưu ý một vài điều đáng chú ý về mã trong Phần 3 của Liệt kê 9. Hai biểu thức for gần phần đầu của mã này gợi ý cho XQuery rằng đây sẽ là một biểu thức nối. Mệnh đề where có khái niệm tương tự như những gì mà mệnh đề này có thể viết bằng SQL để đạt được phép nối. Nhưng cần lưu ý rằng một nút tác giả có thể có nhiều ISBN, đòi hỏi mệnh đề where thực sự có nghĩa là: "ISBN của cuốn sách này ở đâu trong số các ISBN của tác giả". Điều này giống hơn với mệnh đề con select bên trong một mệnh đề where của SQL, nhưng cú pháp XQuery có vẻ trực quan và tự nhiên hơn. Và chắc chắn biểu thức XQuery ngắn gọn hơn.

Liệt kê 10. Các kết quả từ một biểu thức nối XQuery
View Code:

<books-complete-info>
  <book>
    <title>ANSI Common LISP</title>
    <isbn>978-0-13-370875-2</isbn>
    <name>Paul Graham</name>
  </book>
  <book>
    <title>On LISP</title>
    <isbn>978-0-13-030552-7</isbn>
    <name>Paul Graham</name>
  </book>
  <book>
    <title>Neural Networks in the Capital Markets</title>
    <isbn>978-0-471-94364-8</isbn>
    <name>Apostolos-Paul Refenes</name>
  </book>
  <book>
    <title>Neural Networks in Financial Engineering</title>
    <isbn>978-981-02-2819-4</isbn>
    <name>Apostolos-Paul Refenes</name>
  </book>
</books-complete-info>
Bookmark and Share

0 comments:

Post a Comment

Next previous home

Cộng đồng yêu thiết kế Việt Nam Thiet ke website, danang