Định vị các phần cụ thể của tài liệu XML với XPath, Phần 2

Cải tiến kết quả của XPath sử dụng vị từ phù hợp

Phần 1 của bài viết này đã đưa cho bạn biết lợi ích của XPath. Cách sử dụng ký tự dấu gạch chéo, các ký tự thay thế, tập hợp và văn bản đơn giản, đồng thời bạn cũng học cách làm thế nào xác định được các phần tử và các thuộc tính ở mọi vị trí của tài liệu XML. Tuy nhiên thỉnh thoảng có lúc bạn cần làm việc dựa vào tên của nút trong tài liệu. Khi sử dụng các vị từ để thực hiện tìm kiếm bạn có thể đánh giá được các giá trị của các thuộc tính và của nút cha và của các nút con của phần tử mục tiêu. Hơn thế nó cho phép bạn tìm một tập hợp các nút mở rộng và thực hiện cải tiến hay chọn lọc các cài đặt để bạn có thể thêm vào các khẳng định để cho phép các XPaths của bạn tìm kiếm chính xác các nút bạn muốn.

Brett McLaughlin , Tác giả, biên tập, O'Reilly Media

Brett McLaughlin là tác giả có nhiều sách bán chạy nhất và được trao tặng nhiều giải thưởng cao. Các sách của ông đã bán với hơn 100,000 bản gồm các thể loại về ngôn ngữ lập trình, home theater, phân tích và thiết kế. Ông đã và đang vẫn tiếp tục công việc viết, chủ biên và xuất bản các sách về công nghệ trong hơn một thập niên vừa qua, ngoài các công việc yêu thích là viết sách ông còn tham gia chơi guitar và nô đùa với hai cậu con trai của ông tại nhà cùng với người vợ của ông



17 06 2008

Trước khi bạn bắt đầu

Nghiên cứu làm thế nào để nhận được bài viết này và làm thế nào để thực hiện nó.

Giới thiệu về bài viết này

Bài viết này tập trung mô tả chi tiết về XPath, cho phép bạn xác định các phần khác nhau của tài liệu XML bằng cách sử dụng cú pháp dưới dạng thư mục. Bạn sẽ học cú pháp của XPath và bạn sẽ làm việc với các công cụ để thực thi XPath tương ứng. Đồng thời, sau khi bạn hoàn thành toàn bộ bài viết này bạn sẽ nắm được các khái niệm cơ bản của XPath và bạn sẽ hiểu rõ hơn cách sử dụng XPath trong các ứng dụng của bạn.

Các mục tiêu

Các từ viết tắt trong bài viết này

  • API: giao diện lập trình ứng dụng
  • HTML: Ngôn ngữ đánh dấu siêu văn bản
  • URI: Uniform Resource Identifier
  • W3C: World Wide Web Consortium
  • XHTML: Ngôn ngữ đánh dấu siêu văn bản mở rộng
  • XML: Ngôn ngữ đánh dấu mở rộng
  • XSL: Extensible Stylesheet Language
  • XSLT: XSL Transformations

Phần 2 của bài viết này tập trung vào việc sử dụng các vị từ và đưa ra các vị từ phù hợp trong XPath của bạn. Bao gồm các lựa chọn XPath khác nhau được cung cấp cho việc tìm kiếm của bạn. Nó cũng mô tả cách làm thế nào xây dựng các vị từ phức tạp thành tập câu lệnh phức tạp của các truy vấn bằng cách chỉ sử dụng cú pháp XPath chuẩn.

Bạn cũng sẽ bắt đầu hiểu các ý tưởng ứng dụng của XPath và bạn cũng sẽ biết khi nào XPath là lựa chọn tốt nhất so với công nghệ XML khác như XQuery. Cuối cùng bạn sẽ biết cách làm việc với các kiểu dữ liệu đặc biệt khi bạn thực hiện so sánh các giá trị thuộc tính có giá trị số.

Điều kiện tiên quyết

Điều kiện cần thiết để bạn học bài viết này đó là bạn phải đã đọc và làm việc với Phần 1 (xem Tài nguyên). Bài viết đó giới thiệu đầy đủ các khái niệm cơ bản của XPath và cũng mô tả chi tiết về các nút và các thực hiện đánh giá các biểu thức XPath từng phần từng phần một.

Thêm vào đó, bài viết này được viết bởi nhóm các tác giả và các lập trình về tài liệu XML. Vì thế bạn cũng cần biết cách đọc, viết và thực thi với XML. Bạn cũng nên có các khái niệm về XML, bao gồm:

  • Elements - Các phần tử hay còn gọi là các thành phần
  • Attributes - Các thuộc tính
  • Text - Văn bản
  • The root element - Phần tử gốc

Mặc dù không yêu cầu nhưng nếu bạn đã làm việc với DOM thì điều đó rất tốt để giúp bạn hiểu về các nút. Nếu muốn nghiên cứu về DOM, ghé thăm Tài nguyên để tìm kiếm một số đường dẫn liên quan. Đồng thời bạn cũng nên tìm hiểu rõ về các phần liên quan đến nút trong Phần 1 của bài viết này.

Bài viết này sẽ đề cập đến và xác định một số API khác nữa bao gồm: XSL, XSLT và XPath. Nếu có sự hiểu biết về từng phần này là rất tốt mặc dù không yêu cầu bắt buộc. Để có nhiều thông tin hơn về các phần này, ghé thăm Tài nguyên trong bài viết này.


Đặt tham biến môi trường cho ví dụ

Các tài liệu và cài đặt áp dụng cho bài viết này được sử dụng lại từ trong phần I vì thế nếu bạn đã làm việc được trong Phần 1 thì chúng ta sẵn sàng để đến Phần 2.

Bạn cũng sẽ làm việc với tài liệu XML thông qua bài viết này. Bạn cần phải có tài liệu để truy cập đến trong máy của bạn và phải nắm được cấu trúc cơ bản của tài liệu tương ứng đó. Thêm vào đó bạn cũng cần có các công cụ để thực thi biểu thức XPath của bạn và trả lại kết quả dựa trên lựa chọn của bạn. Phần này diễn tả làm cách nào để có thể làm được các ví dụ của bài viết dựa trên phần môi trường cá nhân đã có.

Thật không may mắn công cụ để đánh giá xác định XPath là không được xác định cho từng hệ thống xử lý khác nhau. Có một vài công cụ được tải xuống dưới dạng tệp .EXE và chạy trên nền Microsoft® Windows® nhưng sẽ không làm việc được trên Mac OS X. Tương tự, các công cụ để làm việc được trên hệ điều hành Mac OS X nhưng không chạy được trên Windows. Trong khi bạn sử dụng các chương tình Java™ và các lớp để tạo ra hệ thống độc lập với làm việc bài báo này thì tập trung vào nghiên cứu XPaths hơn là tập trung vào nghiên cứu bấy kỳ các ngôn ngữ lập trình khác

Theo như các phần trên đã hiển thị chi tiết cách làm thế nào để có được các công cụ để làm việc với XPath trên cả Windows và Mác OS X. Bạn hãy chọn công cụ mà bạn muốn sử dụng để làm. Mỗi một công cụ, tất cả các cú pháp và các ví dụ hiển thị một cách đầy đủ vì thế bạn sẽ có được công cụ tương ứng của bạn để đánh giá các biểu thức XPath.

Đánh giá các biểu thức XPath trên Windows

Một trong các công cụ tốt nhất để làm việc với XPath trên hệ điều hành Windows đó là Stylus Studio (xem tại Tài nguyên để có đường dẫn tới trang Stylus Studio Web và tải về). Tải bất kỳ một trong các phiên bản sau —Enterprise Suite, Professional Suite, hay Home Edition— và cài đặt trên nền hệ điều hành tương ứng

Mỗi khi bạn cài Stulus Studio bạn phải chắc chắn có thể xử lý được XPaths từ phần đầu tiên của bài báo này; sau đó bạn sẽ biết các để sẵn sàng làm gì tiếp theo. Kết quả màn hình của bạn sẽ có dạng như Hình 1.

Hình 1. Stylus Studio cho phép đánh giá xác định biểu thức XPath
Stylus Studio cho phép đánh giá xác định biểu thức XPath

Đánh giá biểu thức XPath trên hệ điều hành Mac OS X

Các công cụ để làm việc với XPath trên hệ điều anh Mác OS X— mà không sử dụng lớp Java— là có ít cải tiến và tinh tế hơn so với làm việc trên hệ điều hành Window. Hầu hết các công cụ được sử dụng là AquaPath, là phần mềm mã nguồn mở và tải miễn phí (ghé thăm trang để tải về tại Tài nguyên). Tải AquaPath dưới dạng ảnh của đĩa và đơn giản chỉ cần thực hiện di chuyển ứng dụng AquaPath từ hình ảnh thể hiện vào thư mục ứng dụng Web của bạn.

Nháy đúp chuột vào ứng dụng AquaPath cài đặt mới, bạn sẽ nhìn thấy màn hình có dạng giống như trong Hình 2.

Hình 2. AquaPath cung cấp cách xử lý XPath trên Mac OS X
AquaPath cung cấp cách xử lý XPath trên Mac OS X

Có thể trông nó chưa giống nhiêu nhưng khi bạn bắt đầu tải các tài liệu XML và đánh vào đó biểu thức XPath thì công cụ này —trông giống như Stylus Studio— khi thực hiện

Kiểm tra tài liệu XML

XPath là làm việc nhiều về XML so với bất kỳ ngôn ngữ lập trình nào khác. Vì thế hầu hết các chương trình đều sử dụng XPath thông qua các API kể từ Java hay C# chính vì vậy bài viết này tập trung vào xử lý các XPath dựa trên tài liệu XML. Chính vì thế mà nói rằng làm việc với tài liệu XML là làm việc với XPath. Để phục vụ cho bài viết này thì bạn cần có tài liệu XML minh họa ngắn gọn (tầm khoảng 50 dòng) và tài liệu này có một số các phần tử cũng như các thuộc tính mang giá trị dữ liệu nào đó.

Ví dụ 1 hiển thị một phần của tài liệu XML được sử dụng, tài liệu này được Ant xây dựng từ Apache Xerces2 Java Parser. Tài liệu này bao gồm nhiều nhưng trong ví dụ này chỉ hiển thị tóm tắt. Tuy nhiên bạn có thể tải đầy đủ tài liệu XML từ Tài nguyên.

Ví dụ 1. Tài liệu mẫu XML cho bài viết này
<?xml version="1.0"?>
<!--
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
-->
<!-- ===================================================================

Read the README file for build instruction.

Authors:
  Stefano Mazzocchi <stefano@apache.org>
  Anupam Bagchi     <abagchi@apache.org>
  Andy Clark, IBM

   $Id: build.xml 567790 2007-08-20 19:16:53Z mrglavas $

==================================================================== -->
<project default="usage" basedir=".">
	
  <!-- Xerces Java directories -->
  <property name="build.dir" value="./build"/>
  <property name="data.dir" value="./data"/>
  <property name="docs.dir" value="./docs"/>
  <property name="samples.dir" value="./samples"/>
  <property name="src.dir" value="./src"/>
  <property name="tests.dir" value="./tests"/>
  <property name="tools.dir" value="./tools"/>

  <!-- enable compilation under JDK 1.4 and above -->
  <taskdef name="xjavac" classname="org.apache.xerces.util.XJavac">
    <classpath>
      <pathelement location="${tools.dir}/bin/xjavac.jar"/>
    </classpath>
  </taskdef>

  <!-- Allow properties following these statements to be overridden -->
  <!-- Note that all of these don't have to exist.  They've just been defined
       in case they are used. -->
  <property file="build.properties"/>
  <property file=".ant.properties"/>
  <property file="${user.home}/.ant.properties"/>
  <property file="default.properties"/>
 
  <target name="init">
    <property name='parser.Name' value='Xerces-J'/>
    <property name='parser.name' value='xerces-j'/>
    <property name='parser.shortname' value='xerces'/>
    <property name='parser.Version' value='2.9.1'/>
    <property name='parser.version' value='2.9.1'/>
    <property name='parser_version' value='2_9_1'/>

    <property name='deprecatedjar.parser' value='xerces.jar'/>
    <property name='jar.apis' value='xml-apis.jar'/>
    <property name='jar.parser' value='xercesImpl.jar'/>
    <property name='jar.samples' value='xercesSamples.jar'/>
    <property name='jar.dv' value='xercesDV.jar'/>
    <property name='jar.resolver' value='resolver.jar'/>
    <property name='jar.serializer' value='serializer.jar'/>
    <property name='jar.junit' value='junit.jar'/>
<!-- Lots more properties here... -->
  <!-- =================================================================== -->
  <!-- Prepares the build directory                                        -->
  <!-- =================================================================== -->
  <target name="prepare" depends="init">
    <mkdir dir="${build.dir}"/>
  </target>

  <!-- =================================================================== -->
  <!-- directory creation and file copying common to all configurations    -->
  <!-- =================================================================== -->

  <target name="prepare-common" depends="prepare">
    <!-- create directories -->
    <mkdir dir="${build.src}"/>
    <mkdir dir="${build.dest}"/>
    <mkdir dir="${build.dest}/META-INF"/>
    <mkdir dir="${build.dest}/META-INF/services"/>

    <copy 
      file="${src.dir}/org/apache/xerces/jaxp/javax.xml.parsers.DocumentBuilderFactory"
      tofile="${build.dest}/META-INF/services/javax.xml.parsers.DocumentBuilderFactory"/>

    <copy 
      file="${src.dir}/org/apache/xerces/jaxp/javax.xml.parsers.SAXParserFactory"
      tofile="${build.dest}/META-INF/services/javax.xml.parsers.SAXParserFactory"/>

    <copy 
      file="${src.dir}/org/apache/xerces/jaxp/datatype/javax.xml.datatype.DatatypeFactory"
      tofile="${build.dest}/META-INF/services/javax.xml.datatype.DatatypeFactory"/>
  	
    <copy file=
       "${src.dir}/org/apache/xerces/jaxp/validation/javax.xml.validation.SchemaFactory"
      tofile="${build.dest}/META-INF/services/javax.xml.validation.SchemaFactory"/>

    <copy file="${src.dir}/org/apache/xerces/parsers/org.xml.sax.driver"
      tofile="${build.dest}/META-INF/services/org.xml.sax.driver"/>

  </target>
<!-- Lots more targets and tasks here... -->
</project>

Hãy đảm bảo rằng bạn đã có xerces-build.xml và công cụ XPath đã được cài đặt và sẵn sàng sử dụng. Và bạn đã sẵn sàng để bắt đầu.


Thực hiện lựa chọn dựa vào các vị từ

Tất cả các XPath bạn đã viết trong phần 1 của bài viết này tập trung vài việc xác định các nút trong từng bước tại một thời điểm khi bạn di chuyển đến nút địch. Ví dụ, trong biểu thức XPath //target/copy/fileset, nút đích là fileset là nút chứa trong phần tử copy, là nút được chứa trong phần tử target, với phần tử target được đặt ở bất kỳ vị trí nào của tài liệu nguồn. Công việc này là thực hiện hiệu quả khi bạn cần tìm tập hợp các nút được xác định dựa vào các phần tử hoặc các thuộc tính (hoặc dựa vào cả nếu có thêm dấu |).

Tuy nhiên, XPaths cũng có giới hạn của nó. Chúng hữu dụng —và trong rất nhiều trường hợp chúng là những gì bạn cần— nhưng chúng không thu được thuận lợi của các thông tin trong tài liệu XML. Ví dụ, bạn không có công cụ để cho phép sử dụng tất cả các giá trị của các thuộc tính trong tài liệu XML gốc. Bạn cũng không có cách nào để sử dụng những kết quả trả lại tương ứng đó khi các phần tử chỉ có thể là các thuộc tính hay các phần tử con. Bạn có thể trả lại các thuộc tính hay các phần tử con bằng cách sử dụng XPath có dạng như sau //target/copy/*, cái này trả lại các phần tử con của phần tử copy là các phần tử nằm trong các phần tử target. Nhưng nếu bạn không muốn những phần tử con này? Nếu bạn muốn tất cả các phần tử copy mà có chứa phần tử con?

Khi bạn muốn giới hạn hay chọn lọc các kết quả của bạn dựa trên điều kiện thông qua tên của các phần tử và các thuộc tính và đường dẫn tới những phần từ và thuộc tính bạn cần vị từ. Vị từ là một biểu thức rút gọn được nhúng vào cặp dấu ngoặc vuông ([]), đó là ký hiệu để chỉ đến một tập hợp nút trong biểu thức XPath của bạn. Vị từ cho phép bạn cải tiến các XPath của bạn và thêm vào lượng lớn các ràng buộc vào công cụ XPath.

Thêm chọn lựa cho thuộc tính và phần tử riêng rẽ

Biểu mẫu cơ bản nhất là nhận tập hợp nút và kiểm tra để xem có các nút nào có các thuộc tính và các phần tử con.

Thêm chọn lựa cho thuộc tính riêng lẻ

Hỗ trợ bạn cách để tìm tất cả các phần tử copy nằm trong các phần tử target. Để đơn giản hãy sử dụng XPath có dạng như: //target/copy. Tuy nhiên trong tệp mà Ant xây dựng — có tên là xerces-build.xml, là tệp ví dụ của bài viết này— các phần tử copy được chia làm hai dạng:

  • Phần tử rỗng: Có thuộc tính file và thuộc tính tofile, trong đó tệp dùng để copy tạo thành tệp mới để sử dụng. Biểu mẫu này được cho dưới dạng như sau:
     <copy
                                file="${src.dir}/org/apache/xerces/parsers/org.xml.sax.driver"
                                tofile="${build.dest}/META-INF/services/org.xml.sax.driver"/>
  • Biểu mẫu với các phần tử con: Thuộc tính todir là năm trong phần tử copy, nhưng các thông tin liên quan đến copy là trong các phần tử con. Biểu mẫu này có dạng như sau:
     <copy todir="${build.src}">
                                <fileset dir="${src.dir}" includes="org/apache/**
                                org/w3c/dom/html/HTMLDOMImplementation.java"
                                excludes="**/classfiles_updated **/CVS* **/.#* **/XMLMessages.java
                                **/DatatypeContentModel.java **/ComplexTypeInfo.java **/v1/** **/v2/**
                                javax.xml.parsers.ConvertToURI.java"> </fileset>
                                </copy>

Biểu thức XPath //target/copy trả lại cả hai trong số biểu mẫu này. Hơn thế nữa, nếu bạn muốn khôi phục lại chính xác phần tử fileset nằm trong phần tử copy, bạn có thể sử dụng XPath có dạng như //target/copy/fileset. Bạn cũng có thể nhanh chóng khôi phục todir hay các thuộc tính file sử dụng XPath có dạng //target/copy/@todir hay //target/copy/@file. Trong trường hợp này, bạn lựa chọn hoặc biểu mẫu của copy với các phần tử con chứa bên trong (bằng việc lựa chọn thuộc tính todir attribute) hoặc biểu mẫu rỗng (bằng việc lựa chọn thuộc tính file). Trong cả hai trường hợp, các tập hợp nút kết quả vẫn chứa các thuộc tính, nhưng phải các phần tử của copy.

Nhưng nếu muốn chỉ trả lại các phần tử copy với thuộc tính file? Khi đó cần phải xác định cho phù hợp với từng nút mục tiêu tương ứng. Ví dụ 2 hiển thị cú pháp để sử dụng vị từ để phù hợp thuộc tính.

Ví dụ 2. Lựa chọn các phần tử dựa trên sự tồn tại của thuộc tính
 //target/copy[@file]

Di chuyển đến phần đầu và đánh biểu thức XPath vào trong bộ xử lý XPath của bạn. Bạn sẽ nhận được các kết quả trông có dạng như Hình 3.

Hình 3. Cho phép chỉ lựa chọn phần tử copy với thuộc tính tệp
Cho phép chỉ lựa chọn phần tử copy với thuộc tính tệp

Phần đầu tiên của XPath này trông có dạng như: //target/copy. Phần tiếp theo là đặt trong cặp dấu ngoắc vuông: [@file]. Dấu ngoắc vuông dùng để xác nhận. Điều này có nghĩa rằng cái đó được đánh giá nhưng bộ xử lý thực hiện trên từng nút trong tập nút trả lại bằng cách quãng XPath. Vì thế để có các nút được trả lại bằng //target/copy, nút này được đánh giá một lần nữa bằng vị từ [@file]. Vị từ này chỉ ra rằng bạn cần các thứ của có dạng khi bỏ cặp dấu đóng ngoặc vuông @file. Biểu thức XPath này chỉ định rằng làm việc với thuộc tính có tên file.

Sau đó đặt tất cả các phần này vào với nhau thì mỗi nút từ //target/copy được kiểm tra để trả lại xem thuộc tính có phải có tên là file. Nếu kết quả là đúng thì tập hợp các nút sẽ được trả lại trong tập kết quả. Nếu có bất kỳ các nút nào không có thuộc tính file thì trả lại kết quả false và nút này sẽ bị từ chối. Vì thế tập các nút kết quả được mô phỏng trong Hình 3, Hình này chỉ hiển thị các phần tử copy mà bạn muốn là các phần tử chứa thuộc tính file trong đó.

Cách làm là tương tự để nhận phần tử copy nhưng với các thuộc tính khác, giống như thuộc tính todir. Ví dụ 3 Thể hiển công việc này.

Ví dụ 3. Lựa chọn các phần tử trên các thuộc tính tồn tại khác
                     //target/copy[@todir]

Thêm điều kiện kiểm tra cho từng phần tử con riêng biệt

Thực hiện kiểm tra các phần tử con là đơn giản hơn việc thực hiện kiểm tra các thuộc tính. Với mục đích bạn cần tất cả các phần tử copy kèm với các phần tử con fileset của nó. Tuy nhiên, khó có thể giả thiết rằng phần tử copy có các phần tử con bởi vì nó có thể có cả các thuộc tính todir. Hơn thế nữa khi thực hiện kiểm tra thuộc tính bạn muốn lựa chọn các phần tử copy dựa trên sự tồn tại của từng phần tử con riêng biệt. Bạn có thể sử dụng XPath dưới dạng như trongVí dụ 4.

Ví dụ 4. Lựa chọn các phần tử dựa trên sự tồn tại của phần tử con
                    //target/copy[fileset]

Bạn sẽ nhận được các kết quả trong Hình 4. Chú ý rằng không phải tất cả các phần tử copy đều được lựa chọn mà chỉ những phần tử được chỉ định là phần tử con mới được chọn.

Hình 4. Chỉ các phần tử copy tương ứng tương ứng với phần tử con fileset được lựa chọn
Các vị từ thực thi việc chọn lọc dựa trên các phần tử con như là các thuộc tính

Rõ ràng nhận thấy rằng một tập hợp nút được sinh từ biểu thức XPath //target/copy, sau đó vị từ [fileset] mới được áp dụng tiếp. Khi không có ký tự @, từ fileset được hiểu rằng như phần tử con của tập phần tử hiện tại. Vì vậy tất cả các phần tử copy gồm cả các phần tử con có tên fileset đều nhận giá trị true, và các phần tử này được trả lại bởi biểu thức XPath. Các phần tử copy mà không có phần tử con là sẽ không được trả lại.

Các vị từ có thể áp dụng cho nhiều mức lồng nhau

Bạn không bị giới hạn để có được các thuộc tính của tập hợp các nút trong ví dụ hiện tại thậm chí cũng không giới hạn các phần tử con của phần tử đó. Điều đó có nghĩa là thay vì muốn có các phần copy mà chứa phần tử con fileset, bạn cần chỉ chính xác phần tử targetcontain những phần tử copy này. Vì vậy khi bạn muốn tìm kiếm các phần tử target với các phần tử lồng copy, thì bạn cần phải xác định được phần tử con lồng có tên là (fileset). Sự thực hiện này bạn có thể thấy rõ trong Ví dụ 5.

Ví dụ 5. Lựa chọn các phần tử dựa trên sự tồn tại của các phần tử con
                    //target[copy/fileset]

Khi thực hiện ví dụ này, kết quả của bạn sẽ có dạng như Hình 5.

Hình 5. Biểu thức này thực hiện lựa chọn chỉ các phần tử copy với các con lồng riêng biệt
Biểu thức này thực hiện lựa chọn chỉ các phần tử copy với các con lồng riêng biệt

Bạn có thể nhận được kết quả nhanh chóng bằng cách sử dụng các vị từ trong biểu thức XPath của bạn. Từ đó bạn cũng có thể xây dựng được nhiều vị từ XPath phức tạp hơn, ví dụ như trong Ví dụ 6.

Ví dụ 6. Các vị ngữ có thể có vài mức lồng nhau
                    //target[java/classpath/pathelement/@path]

Hình 6 hiển thị các kết quả tập hợp nút. Trong trường hợp này chỉ có một nút phù hợp với tài liệu nguồn.

Hình 6. Các vị từ có thể kết hợp phần tử và các đường dẫn thuộc tính
Hầu hết các XPaths cũng làm việc như một predicates

XPaths có thể làm cho bản nản chí một chút đặt biệt khi mà vị từ là rất dài trong một biểu thức XPath. Tuy nhiên nếu bạn thực hiện suy nghĩ từng bước từng bước một bạn sẽ thấy có ít rắc rối để làm việc với chúng. Cuối cùng, vấn đề phức tạp có thể xảy ra khi mà trả lại bất kỳ tập hợp các nút tương ứng của biểu thức XPath dài. Với việc sử dụng vị từ và phần tử cũng như thuộc tính phù hợp bạn sẽ không mất nhiều thời gian để kết thúc biểu thức XPath của bạn ở tại vị trí nút bạn muốn trả lại.

XPath có thể có nhiều vị từ khác nhau

Một trong những mấu chốt chính của khóa học này là biểu thức XPath được tiến hành đánh giá từng phần từng phần một. Với từng dấu gạch chéo bạn nhìn thấy thì tập hợp nút được đánh giá và sau đó phần còn lại của biểu thức XPath liên quan đến các nút mới được đánh giá tiếp. Khi đó bạn thêm các vị từ vào để trộn chúng lại với nhau mà không làm thay đổi giá trị. Vì lý do này bạn có thể thêm nhiều vị tự vào coi như một phần của biểu thức XPath. Bạn dễ dàng thêm từng vị từ vào tập hợp nút bạn muốn. Ví dụ 7 hiển thị XPath trở lên đơn giản khi sử dựng thêm các vị từ.

Ví dụ 7. Các vị từ có thể lồng nhau ở một số mức
                    //target[@depends]/jar[metainf]

Tập nút kết quả được hiển thị trong Hình 7. Chú ý rằng không có phần tử gì đặc biệt trong tập hợp nút này Chỉ có điều khác biệt duy nhất đó là bạn có thể thực hiện trích lọc ở một số mức khác nhau của biểu thức XPAth.

Hình 7. Biểu thức XPath có thể có nhiều hơn một vị từ
Biểu thức XPath có thể có nhiều hơn một vị từ

Thực hiện XPath này từng bước từng bước một:

  1. Xử lý tất cả các phần tử target mà không quan tâm đến vị trí xuất hiện của phần tử đó trong tài liệu.
  2. Với mỗi nút trong tập hợp đó, bộ xử lý thực hiện áp dụng vị từ [@depends]. Nếu nút có thuộc tính tên là depends thì bộ xử lý thêm nút đó vào tập kết quả. Nếu không thì bỏ qua nút đó.
  3. Với mỗi nút còn lại, bộ xử lý kiểm tra để xem có bất kỳ phần tử con nào tên là jar. Nếu có bộ xử lý cất giữ nút đó vào tập kết quả.
  4. Với mỗi phần tử jar trong tập hợp kết quả bộ xử lý áp dụng vị từ [metainf] vào đó. Vì thế phần tử jar có chứa phần tử con tên là metainf thì bộ xử lý cất giữ nút đó trong tập kết quả.
  5. Khi mà biểu thức XPath được thực hiện thành công bộ xử lý trả lại các nút như là một phần của tập hợp.

Thực hiện tập các bước và các đánh giá đó, bộ xử lý được thực hiện là rất đơn giản. Nó thường gồm hai biểu thức XPath khác nhau trong đó một là biểu thức với vị từ và thực hiện kết hợp với biểu thức XPath thứ hai thành một biểu thức XPath đơn. Lợi ích chính của việc thực hiện xử lý từng bước từng bước (hay từng phần từng phần) của biểu thức XPath là: bạn có thể áp dụng bất kỳ vị từ nào cũng như bất kỳ đường dẫn tại bất kỳ trạng thái nào bạn đều nhận được các kết quả dưới dạng vị từ mà không quan tâm đến cú pháp mở rộng hay cú pháp ít sử dụng.


Lựa chọn các nút thông qua vị trí của nó

Mỗi khi bạn thêm một vị từ vào hộp Xpath của bạn bạn sẽ mở ra cơ hội lớn hơn cho việc lựa chọn. Vì thế bạn nên nghiên cứu cách làm thế nào để cải tiến tập các nút của bạn dựa trê các thuộc tính và các phần tử con của nút đó. Một cách tiếp cận đơn giản, trước tiên bạn tới thăm nút first trong danh sách, nút last, hoặc một vài nút liên quan khác. Trong trường hợp này, bạn nên lựa chọn các nút không dựa vào cấu trúc tài liệu XML nhưng dựa vào position của nút.

Đối với các nhà lập trình điều này thật phù hợp. Trong bất kỳ ngôn ngữ nào đều hỗ trợ danh sách và vòng lặp, nó cho phép gộp phần tử vào một danh sách bằng cách xác định vị trí tương ứng của phần tử được cho dưới dạng mảng chỉ số của phương thức giống như firstChild() hay get(list.size()-1). XPath cung cấp vị trí phù hợp trong các vị từ để cho phép bạn nhận được các nút cần thiết trong các biểu thức XPath của bạn.

Lựa chọn phần tử đầu tiên hay phần tử cuối cùng

Để lựa chọn một phần tử từ một tập hợp cách đơn giản nhất là duyệt từ nút đầu đến nút cuối của tập hợp. Bạn đã biết rằng XPath được đánh giá và trả lại kết quả dưới dạng một tập hợp các nút nên vì thế bạn phải biết cách để nhận các nút thông qua vị trí của nó bằng cách sử dụng cú pháp dạng ký hiệu.

Lựa chọn phần tử đầu tiên trong tập hợp

Mỗi một tập hợp nút là cần một danh sách chỉ số tương ứng. Khi đó bạn có thể truy cập tới từng phần tử trong tập hợp nút thông qua chỉ số dưới dạng vị từ. Để nhận được phần tử đầu tiên trong tập hợp nút bạn áp dụ vị từ sau [1]. Ví dụ 8 thực hiện khôi phục phần tử nút đầu tiên trong XPath.

Internet Explorer không phải luôn luôn hiểu được [1] một cách chính xác

Internet Explorer, từ phiên bản 5 đến này có hỗ trợ thực hiện XPath. Trong trình duyệt này, Chỉ số 0 được áp dụng để chỉ tới phần tử đầu tiên trong tập hợp. Vì vậy điều này có thể gây ra lỗi khi thực thi XPath trong trình duyệt. Cho nên bạn hãy cẩn thận nếu muốn thực hiện đánh giá trực tiếp XPath trong Internet Explorer (rất ít khi sử dụng), [1] Lựa chọn nút thứ hai; [0] lựa chọn nút đầu.

Ví dụ 8. Vị từ [1] cho phép lựa chọn phần tử đầu tiên trong tập hợp
 //target[@depends]/java[1]

Thực hiện xử lý XPath này trong công cụ của bạn và bạn sẽ nhận được kết quả có dạng như trong Hình 8.

Hình 8. Vị từ [1] cho phép lựa chọn phần tử đầu tiên trong tập hợp
Vị từ [1] cho phép lựa chọn phần tử đầu tiên trong tập hợp!

Hãy thử xem khi một số được lựa chọn ở đây. XPath này sẽ trả lại ba nút!. Như vậy, XPath tiến hành xử lý cùng lúc nhiều nút. Tìm hiểu kỹ biểu thức này và cũng tìm hiểu cẩn thận xem điều gì xảy ra:

  1. Bộ xử lý xác định được tất cả các phần tử target trong tài liệu. Tập nút được bao gồm từng phần tử trong số đó và cả vị trí tương ứng của phần tử đó.
  2. Bộ xử lý áp dụng vị từ đầu tiên [@depends]. Khi đó tập nút chỉ chứ các phần tử target các thuộc tính depends được tạo ra.
  3. Phần tiếp theo của XPath bắt đầu từ dấu gạch chéo (tại phần cuối của //target[@depends]/) sau đó đến dấu gạch chéo tiếp theo, hay là đến phần cuối của XPath. Điều đó có nghĩa là java[1]. Với mỗi phần tử trong tập hiện tại, bộ đánh giá tạo ra một tập các phần tử java. Nhớ lại rằng tập của các phần tử java xảy ra cho từng phần tử target từ các phần trước của biểu thức XPath. Nếu cả ba phần tử phù hợp với //target[@depends] thì có ba tập hợp của các nút được hiển thị ở bên phía phải.
  4. Cho từng tập hợp trong các tập hợp, bộ xử lý áp dụng vị tự [1]. Vì thế mà phần tử đầu tiên trong mỗi tập hợp được trả lại. Điều đó có nghĩa rằng nếu ba nút được đánh giá xử lý thì có ba phần tử đầu tiên.
  5. Bộ xử lý tiến hành hợp tất cả các nút từ các tập hợp và trả lại một kết tập kết quả riêng biệt. Trong trường hợp này, kết của là ba phần tử java, đó là phần tử đầu tiên java nằm phía dưới phần tử có tên target và phần tử này có thuộc tính là depends.

Điều này là lý do tại sao XPath dùng để đánh giá bị chỉ trích. Thậm chí kể cả trong XML, nhiều tác giả và các nhà phát triển đều không muốn sử dụng vị từ [1] trong XPath— thậm chí cả phần cuối cùng của XPath— cũng không đảm bảo chỉ có một phần tử được trả lại.

Lựa chọn nút đầu tiên trong tập kết quả

Có thể bạn quan tâm xem làm thế nào để có thể lựa chọn được phần tử đầu tiên trong tập kết quả cuối cùng. Điều này thì lại rất đơn giản bởi vì XPath cho phép bạn xác định thứ tự xử lý thông qua sử dụng dấu ngoặc đơn để có được kết quả phù hợp. Ví dụ 9 hiển thị XPath cái mà hầu hết được xác định cho Ví dụ 8 nhưng đưa ra nhiều kết quả khác nhau.

Ví dụ 9. Vị từ [1] được áp dụng để chỉ toàn bộ XPath
                    (//target[@depends]/java)[1]

Làm thử ví dụ bày bạn sẽ thấy kết quả giống Hình 9 nếu cần bạn có thể quay lại xem thêm Hình 8.

Hình 9. Bạn có thể sử dụng vị từ [1] để lựa chọn phần tử đầu tiên trong tập các kết quả đã có
Bạn có thể sử dụng vị từ [1] để lựa chọn phần tử đầu tiên trong tập các kết quả đã có

Điều này là quá phức tạp. Tại bất kỳ thời điểm nào bạn bao quanh từng phần của XPath theo hướng song song, khi đó từng phần của XPath được đánh giá đầy đủ trước khi áp dụng cho từng vị từ. Chú ý rằng bạn có thể trình bày lại Ví dụ 9 dưới dạng như (//target[@depends]/java[1])[1]. Tuy nhiên, vị từ [1] đầu tiên là không cần thiết ở đây.

Cũng như thế bạn hãy nhớ rằng chỉ số đầu tiên trong tập hợp đối với tập nút trong XPath luôn luôn là 1, chứ không phải 0.

Lựa chọn phần tử cuối cùng trong tập hợp

Khi bạn muốn lựa chọn nút cuối cùng trong tập hợp có thể bạn không dùng đến toán tử số; chỉ số cuối cùng nào của tập hợp nút được xác định ở đây? Để nhận được nút cuối cùng bạn cần sử dụng một hàm của XPath, hàm đó là: last(). Hàm last() đưa ra kết quả tương ứng với cái bạn mong chờ: Đó là nó trả lại nút cuối cùng trong tập hợp bạn đang áp dụng trên đó. Ví dụ 10 là tương tự ví dụ trong Ví dụ 8.

Ví dụ 10. Vị từ last()] lựa chọn phần tử cuối cùng trongtập hợp
					 //target[@depends]/java[last()]

giống như Ví dụ 8— và cái bạn nhìn thấy trong Hình 8—trả lại nút cuối cùng từ ba tập hợp nút khác nhau. Kiểm tra Hình 10 để xem rõ kết quả này.

Hình 10. Hàm [last()] thực hiện lựa chọn nút cuối cùng trong tập hợp
Hàm [last()] thực hiện lựa chọn nút cuối cùng trong tập hợp

Ngay bây giờ, bạn không cần phải ngạc nhiên vì kết quả đó. Thực tế, bạn có thể thực hiện các bước đơn giản trước đó và thay thế từ "first" trong bước thứ hai và bước cuối thành "last":

  1. Bộ xử lý xác định tất cả các phần tử target ở bất kỳ vị trí nào trong tài liệu.
  2. Bộ xử lý thực hiện với vị từ [@depends] trước. Bộ xử lý tạo tập nút mới chỉ chứa các phần tử target với các thuộc tính depends.
  3. Bộ xử lý thực hiện xử lý phần tiếp theo của XPath đó là java[1]. Với mỗi phần tử trong tập hiện tại bộ xử lý đánh giá tập của các phần tử java. Vì thế ba tập hợp của các nút được nhìn thấy cùng lúc tại thời điểm này.
  4. Với mỗi tập hợp này bộ xử lý áp dụng vị từ [last()]. Vì thế phần tử last trong từng tập hợp được trả lại. Đây là các kết quả trong Ba phần tử cuối cùng.
  5. Bộ xử lý thực hiện hợp tất cả các nút từ ba tập hợp vào thành một tập kết quả riêng. Kết quả là ba phần tử java trong đó cả ban phần tử lastjava đều nằm dưới phần tử có tên target đó là phần tử có thuộc tínhdepends.

Tương tự cách sử dụng của [1] bạn có thể áp dụng last() để cải tiến XPath sử dụng xử lý song song như mô phỏng trong Ví dụ 11.

Ví dụ 11. Vị từ [last()] được áp dụng để cải tiến XPath
                    (//target[@depends]/java)[last()]

Hình 11 hiển thị nút đơn cái được trả lại của biểu thức này.

Hình 11. Bạn có thể sử dụng vị từ [last()] để lựa chọn nút cuối cùng trong tập kết quả
Bạn có thể sử dụng vị từ [last()] để lựa chọn nút cuối cùng trong tập kết quả

Phải nhớ rằng, khi bạn sử dụng [1] hay [last()] trong toàn bộ biểu thức XPath thì kết quả của bạn sẽ luôn hoặc là nút đơn kết quả hoặc là không có nút nào.

Không có hàm first()trong XPath

Có một hàm last() trong XPath nhưng không có tương ứng hàm first(). Nếu mà có hàm này để giải quyết vấn đề Internet Explorer đề cập trong Internet Explorer doesn't always handle [1] correctly. Tuy nhiên, first() là có thể lấy ra kết quả đặc trưng của XPath bởi vì nó có thể không thực sự cần thiết. Theo nguyên tắc xác định vị từ [first()] có thể luôn luôn là tương đương với [1] vì thế không cần phải thêm hàm first() cho ngôn ngữ lập trình.

Trong bất kỳ trường hợp nào cảnh báo này —chỉ ra rằng first() không được coi là hàm XPath — bởi vì một vài bộ xử lý XPath bao gồm kể cả AquaPath đều không có thông báo lỗi khi bạn sử dụng hàm này. Vì vậy XPath giống như (//target[@depends]/java)[first()] đơn giản trả lại tập nút rỗng.

Tập hợp nút có thể rỗng hoặc mang một giá trị

Khi bạn sử dụng toán tử xác định vị trí trong vị từ bạn luôn luôn nhớ rằng không có sự đảm bảo rằng tập nút có một hay nhiều nút thành viên. Trong thực tế cũng không có đảm xác định rằng tập nút có chứa bất kỳ các nút thành viên nào. Ví dụ xem XPath sau /project. Xpath này thực hiện lựa chọn nút gốc của tài liệu ví dụ và cũng theo định nghĩa mỗi tài liệu chỉ có duy nhất một nút gốc vì thế XPath /project[1]/project[last()] đều cùng trả lại chính xác cùng một phần tử: đó là tên của phần tử gốc project.

Có thể gặp phải một chút ít rắc rối — nếu bạn không cẩn thận — khi áp dụng toán tử vị trí trong tập phần tử rỗng. Thử với ví dụ XPath /root cho cùng tài liệu ví dụ này. Kết quả bạn thu được là tập rỗng bởi vì phần tử gốc có tên là project chứ không phải tên root. Nếu bạn áp dụng vị từ định vị bạn có thể áp dụng hoặc chỉ số dưới dạng 1 hoặc hàm giống như last() để áo dụng cho tập rỗng. Kết quả không phải là một lỗi mà đơn giản chỉ là tập rỗng. Mấu chốt ở đâu đó là trong XPath các XPath riêng biệt có thể có nhiều vị từ và lỗi có thể chỉ xảy ra cho một vị từ tương ứng. Trong trường hợp đó không hề có lỗi về mặt cú pháp mà tập nút rỗng không có phần tử đầu và không có phần tử cuối. XPath /root[1] sẽ trả lại giá trị là tập nút rỗng.

Lý do có thể nhầm lẫn — một lần nữa, đặc biệt trong các XPath dài hơn — là bạn phải truy xuống chính xác nơi mà vấn đề xảy ra. Ví dụ, đây là một XPath dài hơn: //target[@depends]/java[@fork]/classpath[@path]/pathelement[last()]. Nếu XPath này trả lại một tập nút rỗng, làm thế nào để bạn nhận biết vấn đề xảy chỗ nào? Bất cứ phần nào của XPath đều có thể trả lại một tập nút rỗng. Nếu không có thành phần target có một thuộc tính depends, bạn nhận được một tập nút rỗng. Nếu có, nhưng không có thành phần con tên là java, bạn cũng nhận được tập nút rỗng. Nếu có thành phần nút con java, nhưng không có nút nào có thuộc tính fork, bạn nhận được một tập nút rỗng, và cứ thế. Tại mỗi thời điểm tính toán, nếu tập nút là rỗng, tất cả các phần còn lại của XPath sẽ hoạt động trên tập rỗng và do đó sẽ trả lại các tập rỗng. (Trong ví dụ này, tập rỗng xảy ra khi classpath[@path] được ước lượng; không có thành phần classpath nào với thuộc tính có tên path trong tài liệu.)

Chọn một số nút bởi vị trí của chúng

Bạn cần biết một hàm quan trọng để sử dụng vị trí trong XPath của bạn: hàm position(). Hàm position() trả lại chỉ số của một nút cụ thể trong tập hiện tại, và cho phép bạn sử dụng chỉ số đó trong XPath. Ví dụ, bạn có thể chọn tất cả các nút có vị trí lơn một chỉ số nào đó, hoặc tất cả các nút trừ nút ở một vị trí nào đó.

Hàm position() trả lại một giá trị số

Xem xét XPath trong Ví dụ 12, nó không chỉ là cách dùng của hàm position(), mà còn đưa ra ví dụ so sánh đơn giản trong một vị từ.

Ví dụ 12. Sử dụng hàm position() để chọn một phẩn của một tập các nút, dựa trên chỉ số của từng nút
                    //target/property[position() < 4]

Ví dụ này trả lại toàn bộ thành phần property, các thành phần này là thành phần con của thành phần target, và vị trí của chúng nhỏ hơn 4 trong tập các nút mà chúng nằm trong. Xem kết quả trong Hình 12.

Hình 12. So sánh hàm position() với một số
So sánh hàm position() với một số

Ví dụ trong Ví dụ 12 che giấu tình huống có thể xảy ra khi sử dụng [1]last(): Vị từ hoạt động trên tập nút hiện tại, chứ không phải toàn bộ XPath. Trong trường hợp này, //target/property[position() < 4] hoạt động giống như (//target/property)[position() < 4] (để ý ngoặc đơn trong XPath thứ hai), nên kết quả trở về giống nhau. Tuy nhiên, trở lại ví dụ XPath trong Ví dụ 8Ví dụ 10, hãy xem Ví dụ 13.

Ví dụ 13. Áp dụng position() vào tập các nút hiện tại, không phải toàn bộ XPath
                    //target[@depends]/java[position() < 3]

Đối với người mới bắt đầu, dường như XPath này không thể trả về nhiều hơn hai nút: các nút tại vị trí 1 và 2. Bây giờ, vị từ ở cuối Ví dụ 13 áp dụng cho mỗi tập các nút được nó xử lý. Trong trường hợp này, nó và toàn bộ XPath không là một. Trong thực tế, Ví dụ 13 trả lại năm nút, chứ không phải hai. Và không có gì là ngạc nhiên khi bạn có thể áp dụng một vị ngữ với hàm position()— như các vị ngữ khác —vào toàn bộ XPath với đóng mở ngoặc đơn. Trong trường hợp này, bạn xem Ví dụ 14.

Ví dụ 14. Bạn cũng có thể áp dụng hàm position() cho toàn bộ XPath
                    (//target[@depends]/java)[position() < 3]

Theo định nghĩa, XPath này có thể trả về nhiều nhất hai nút: nút thứ nhất và thứ hai trong tập các nút kết quả.

Công dụng của position() rất dễ hiểu. Ví dụ 15, chọn tất cả các nút trong một tập trừ nút đầu tiên.

Ví dụ 15. Chọn tất cả các nút trừ nút đầu tiên trong tập hiện hành
 (//target[@depends]/java)[position()
                    > 1]

Ví dụ 16 chỉ chọn nút thứ hai trong một tập.

Ví dụ 16. Bạn có thể chọn một nút với vị trí cụ thể nào đó
 //target/property[position() =
                    2]

Tất nhiên, Ví dụ 16 có chức năng trùng với biểu thức XPath //target/property[2], biểu thức này dễ gõ và đọc hơn rất nhiều.

Ví dụ 17 là một XPath hữu dụng; nó đưa ra một vị ngữ trả lại tất cả các nút trừ nút cuối cùng trong tập hiện hành.

Ví dụ 17. So sánh hàm position() với các hàm khác
 //target[@depends]/java[position()
                    < last()]

Trong ví dụ này, hai hàm được sử dụng cùng nhau. Hàm đầu tiên, position(), lấy vị trí của nút đang được xử lý. Hàm thứ hai, last(), lấy vị trí của nút cuối cùng trong tập các nút đang được xử lý. Hàm này được dùng rất nhiều khi tôi giải thích liên kết SQL-like trong XPath.

Cuối cùng, tôi không nói quá lên rằng, các hàm vị trí này áp dụng cho tập các nút đang được đánh giá, chứ không phải cho tất cả các XPath (trừ khi thành phần trong ngoặc đang chạy). Bạn cần nhận thấy rằng có một vài tập nút khác đều có thể được mở và đánh giá, do đó các thuộc tính như [1][last()] có thể trả về nhiều hơn một nút đơn, và các thuộc tính như [position() < 2][position < last()] có thể trả về số nút nhiều gấp hai hay ba lần số nút mà bạn mong muốn.

position() trả lại một giá trị dạng số

Một cảnh báo cuối cùng trước khi bạn rời khỏi phần các thuộc tính vị trí này: Hàm position() trả về một số là chỉ mục của nút hiện tại. Một thuộc tính chỉ chứa duy nhất chỉ mục của nút hiện tại sẽ trả về giá trị true. Điều đó có nghĩa rằng thuộc tính [position()]luôn luôn trả về giá trị true. Kết quả cuối cùng là một XPath dạng như //target[@depends]/java[position()] trả về cho các nút trong tập kết quả được đánh giá, và nó tương đương với XPath có thuộc tính cuối cùng bị bỏ đi: //target[@depends]/java. Hàm position(), sau đó, chỉ thực sự có giá trị khi được so sánh với một vị trí hoặc dựa vào một vị trí nào đó.


So sánh và lọc các nút dựa trên các giá trị của thuộc tính của nút

Ở một mức độ nào đó, mọi thứ bạn nhìn thấy trong các thuộc tính chỉ là một sự khởi động cho các sự kiện chính trong các thuộc tính: việc so sánh các thuộc tính với các giá trị. Trong khi việc kiểm tra các thuộc tính, các thành phần đã được lắp đặt, và vị trí của các nút là quan trọng, 90% các thuộc tính là sự so sánh của thuộc tính với các giá trị cụ thể

Phổ biến nhất trong loại này là việc so sánh một thuộc tính hoặc phần tử (element) với một giá trị bằng chữ, ví dụ như 32 hoặc init. Tôi sẽ nói về những so sánh phức tạp hơn ở phần dưới, còn bây giờ chúng ta hãy xem xét những so sánh cơ bản trong một thuộc tính.

Bộ lọc dựa trên giá trị của một thuộc tính

Bạn đã hiểu làm thế nào để chọn một thuộc tính trong một XPath. Bạn nên sử dụng những cấu trúc kiểu như //target/@name. Bạn cũng đã hiểu được cách để chọn một phần tử dựa trên thuộc tính của nó: //target[@name]. Cả hai Xpath này đều có tác dụng như một hàm mũ khi bạn so sánh tên (name) của thuộc tính với một giá trị.

So sánh các thuộc tính dựa trên đẳng thức.

Giả sử rằng bạn muốn chọn một phần tử target có một tên (name) thuộc tính là init. XPath trong trường hợp này là cái mà bạn mong muốn, nó nằm trong Ví dụ 18.

Ví dụ 18. Bạn có thể so sánh một thuộc tính với một chuỗi ký tự
//target[@name='init']

Thuộc tính này làm hai thứ, một ngầm định (implicit), một rõ ràng (explicit):

  1. Nó chỉ lựa chọn phần tử target với tên thuộc tính là name. Nếu không có thuộc tính đó, việc so sánh sẽ bị bỏ qua và bất kỳ nút nào mà không có thuộc tính name thì sẽ bị loại ra khỏi tập các nút kết quả.
  2. Điều hiển nhiên xảy ra là: bộ đánh giá xpath (XPath evaluator) so sánh giá trị value của thuộc tính name với chuỗi ký tự init. Nếu các giá trị là trùng khớp thì phần tử target cùng với thuộc tính đó sẽ được thêm vào tập kết quả.

Kiểm tra lại XPath này; bạn nên xem một vài thứ như trong Hình 13 Hình 13.

Hình 13. So sánh giá trị thuộc tính với các chuỗi ký tự
Sử dụng các dấu ngoặc đơn cho chuối ký tự trong các thuộc tính của bạn

Các giá trị bạn so sánh nên đặt trong dấu ngoặc đơn. Dùng dấu ngoặc kép thì việc so sánh sẽ chính xác hơn, nhiên các đặc tả XPath thường được sử dụng trong trình duyệt Web, và giống như biểu thức JavaScript, XPath thường được đặt trong các ngoặc kép. Bằng việc sử dụng dấu ngoặc đơn cho việc so sánh các giá trị, bạn sẽ tránh được việc bỏ qua một biểu thức được bắt đầu bởi ngoặc kép, ví dụ như một thuộc tính của HTML hoặc XHTML.

So sánh các thuộc tính dựa trên bất đẳng thức

Bạn đã biết một số bất đẳng thức trong phần các thuộc tính vị trí (positional predicates).Bạn cũng có thể sử dụng các toán tử đó để thực hiện so sánh. Các toán tử thường được sử dụng nhất là: nhỏ hơn (<), lớn hơn (>), nhỏ hơn hoặc bằng (<=), và lớn hơn hoặc bằng (>=). Các toán tử này thường được sử dụng với các thuộc tính có giá trị dạng số, như trong Ví dụ 19.

Ví dụ 19. Bạn có thể so sánh một thuộc tính với một các giá trị số
//book[@pageCount > 500]

Chú ý rằng XPath trong Ví dụ 19 chỉ là một ví dụ mẫu và nó sẽ trả về một tập nút rỗng nếu được so sánh với xerces-build.xml. Tài liệu ví dụ trong bài viết này không có thuộc tính có giá trị chỉ là số, do đó Ví dụ 19 chỉ là một ví dụ có thể xảy ra.

Trong trường hợp này, các bộ định lượng XPath tự động chuyển đổi các giá trị của thuộc tính thành số khi có thể. Phần còn lại chiếm đa số: các thuộc tính sẽ được kiểm tra (theo các bước ngầm định đã được đề cập ở trên), sau đó giá trị của các thuộc tính sẽ được so sánh ngược lại với chuỗi ký tự của 500. Nếu giá trị thuộc tính nhỏ hơn 500, thì các phần tử được xác định sẽ là một phần của tập kết quả.

Một việc xảy ra ngầm định khác với các thuộc tính dạng số: một thuộc tính phải được chuyển đổi thành số. Do mỗi phần tử phải có một thuộc tính xác định và thuộc tính đó phải được chuyển đổi thành một số, sau đó giá trị của nó sẽ được kiểm tra. Nếu thuộc tính đó không thể chuyển đổi thành một số, bạn sẽ nhận được một tập kết quả rỗng (chẳng có gì xảy ra kể cả khi bạn sử dụng một trong các toán tử như bằng, nhỏ hơn hay lớn hơn).

Không phải mọi chuỗi được tạo ra đều bằng nhau

Nhìn chung, các toán tử bất đẳng thức như nhỏ hơn, lớn hơn thường liên quan đến các giá trị dạng số trong các thuộc tính của tài liệu. Tuy nhiên đó không phải là dạng so sánh bằng duy nhất mà bạn có thể làm việc với. Bạn còn có thể sử dụng những toán tử này để so sánh các giá trị dạng chuỗi. Ví dụ, thử nghiệm với XPath trong Ví dụ 20.

Ví dụ 20. So sánh một thuộc tính có giá trị dạng chuỗi với một chuỗi ký tự
//target[@name > 'start']

XPath này so sánh giá trị của thuộc tính name của mỗi phần tử target với chuỗi ký tự 'start'. Nếu name lớn hơn 'start'— nằm trong XPath nghĩa là các ký tự dạng alphabet được sử dụng, sau đó những nút phù hợp với —target được trả về. Do đó những tên như: usage, tests, và test đều được trả về true trong ví dụ này. Hình 14 chỉ ra một tập con các kết quả trả về.

Hình 14. So sánh các thuộc tính giá trị dạng chuỗi với chuỗi ký tự bằng các toán tử bất đẳng thức.
Bạn có thể tìm thấy các thuộc tính (attributes) theo thứ tự từ điển dựa trên XPath

Những qui tắc bạn muốn đều được thể hiện ở đây. Ký tự đầu tiên được so sánh, rồi đến ký tự thứ hai. Bạn nhận được sự so sánh các ký tự theo thứ tự từ điển khi sử dụng cách so sánh các ký tự theo kiểu này. Tuy nhiên, có vài lời khuyên ở đây, trước tiên là với ký tự viết hoa. Từ All (các ký tự viết hoa) đều được coi là nhỏ hơn các ký tự viết thường (all). Nói cách khác, "S" không chỉ nhỏ hơn 's,' như bạn nghĩ, mà còn nhỏ hơn "a," "b," "f,", ... Do đó, nếu tất cả các tên thuộc tính của bạn đều viết thường, ví dụ như trong XPath sau: //target[@name > 'Test' sẽ trả lại phần tử alltarget. Đó là bởi vì mọi ký tự viết thường trong name, bất kể được bắt đầu bởi ký tự viết thường nào, đều lớn hơn chữ "T" trong từ "Test."

Việc so sánh có thể xảy ra ở bất cứ đâu trong XPath

Giống như mọi thuộc tính khác, bạn có thể so khớp các thuộc tính ở bất cứ nơi đâu trong XPath. Ví dụ 21 là một ví dụ về một số thuộc tính với các thuộc tính được so khớp.

Ví dụ 21. Mọi thuộc tính có thể xuất hiện ở bất cứ đâu trong XPath.
//target[@name='init']/property[starts-with(@name, 'parser')]

Một vài mẹo mới được đưa vào trong XPath này, mặc dù chúng không cản trở gì việc xử lý của bạn. Mọi việc ở đây xảy ra theo từng bước:

  1. Bộ đánh giá (evaluator) tìm ra tất cả các phần tử target, mà không quan tâm đến vị trí của chúng.
  2. Bộ đánh giá áp dụng thuộc tính [@name='init']. Do đó, tất cả phần tử target có thuộc tính name đều là ứng cử viên. Sau đó, bộ đánh giá sẽ so sánh giá trị của thuộc tính name với init. Trong tài liệu mẫu, do tất cả các targets đều có tên duy nhất nên bộ đánh giá sẽ trả về một nút target đơn.
  3. Bộ đánh giá xác định tất cả các thuộc tính của các phần tử property mà nút được xếp trực tiếp với phần tử target.
  4. Bộ đánh giá áp dụng các thuộc tính khác: [starts-with(@name, 'parser')]. starts-with() là một hàm mới với hai đối số:
    • Nút so sánh, có thể là một phần tử, một thuộc tính hoặc đoạn nguyên bản. Nút được đặt tương đối với tập các nút hiện tại
    • Chuỗi ký tự mà giá trị của nút nên bắt đầu bởi nó
    Với mỗi một phần tử property từ bước trước, bộ đánh giá kiểm tra các giá trị của thuộc tính name để xem xem nó có bắt đầu bởi parser không. Nếu có thì bộ đánh giá sẽ thêm nút đó vào tập kết quả.

Thử kiểm tra với XPath này, bạn sẽ nhận được kết quả giống như trong Hình 15.

Hình 15. Kiểm tra xem giá trị thuộc tính có bắt đầu bởi một ký tự nhất định nào không.
Bạn có thể sử dụng hàm starts-with() trong một và vị từ và chỉ ra các nút liên quan bao hàm trong phép so sánh

Chú ý rằng, thậm chí với cả những hàm mới trong XPath này, độ phức tạp đã được tăng lên, vẫn rất dễ để phân tích và hiểu được. Đó là bởi vì bạn có hai khái niệm mấu chốt:

  • XPaths được đánh giá từng mẩu (piece) một, trước tiên là với vị trí hay hướng, sau đó là với các thuộc tính. Mỗi phần khác nhau của XPath được phân biệt bởi một gạch chéo "slash".
  • Mỗi mẫu liên tiếp được đánh giá là có liên quan đến nút được trả lại bởi mẫu trước đó.

Chỉ một mẹo nhỏ là sử dụng hàm như starts-with() xảy ra khi bạn muốn đánh giá nút hiện tại (hơn là một trong những thuộc tính của nó). Ví dụ, lại một lần nữa xem lại Ví dụ 21, nếu bạn muốn trả về các thuộc tính thật sự của nút hơn là các phần tử target có các thuộc tính đó, Ví dụ 22 chính là thứ bạn muốn.

Ví dụ 22. Bạn có thể kiểm tra những nút hiện tại trong các hàm kiểu như starts-with()
//target[@name='init']/property/@name[starts-with(., 'parser')]

Ở đây, bạn không muốn đánh giá nút liên quan đến phần cuối của XPath, mà quan tâm đến bản thân các nút có thể trả về. Bạn có thể sử dụng một dấu chấm đơn (.). Với UNIX® và các trình shell users, cái này cũng giống như cú pháp của thư mục hiện hành, do đó nó nên được làm giống nhau. XPath này trả về tên bản thân các thuộc tính name trong tập kết quả.

Nhanh chóng bắt kịp các hàm so khớp chuỗi từng phần

Bạn có thể sử dụng nhiều hàm hơn trong các thuộc tính để so khớp chuỗi. Hàm thường dùng nhất là: starts-with(), mà bạn thường nhìn thấy và hàm ends-with(), chúng thường khá phụ thuộc vào trực giác. Ví dụ 23 Chỉ ra một ví dụ về hàm ends-with().

Ví dụ 23. ends-with() đối lập với starts-with()
//@*[ends-with(., 'version')]

XPath này chọn tất cả nút thuộc tính @*) ở mọi nơi trong tài liệu (được xác định bởi hai gạch chéo //). Sau đó, với mỗi nút này, nó kiểm tra xem giá trị thuộc tính có kết thúc bởi chuỗi 'version'. Có 9 trường hợp xảy ra ở đây trong cùng một tài liệu. Bạn hãy thử XPath này trên AquaPath hoặc Stylus Studio để xem kết quả.

Một tiện ích khác của hàm so khớp chuỗi ký tự là hàm substring(). substring() chứa ba đối số:

  1. Nút đánh giá: đối số này cũng giống như đối số đầu tiên trong hai hàm starts-with()ends-with().
  2. Chỉ số chỉ ra vị trí bắt đầu của chuỗi kết quả.
  3. Chỉ số chỉ ra vị trí kết thúc của chuỗi kết quả.

Ví dụ: substring('name', 1, 3) sẽ trả về chuỗi kết quả là 'nam'. Tất nhiên là bạn hay sử dụng hàm này trong XPath giống như bạn nhìn thấy trong Ví dụ 24.

Ví dụ 24. Việc sử dụng hàm substring() cùng với tên của một nút thông qua hàm name()
(//* | //@*)[substring(name(), 1, 5) = 'class']

Đây cũng là một tiện ích nhỏ khá thú vị của XPath. Trước tiên, mọi nút thuộc tính và phần tử trong tài liệu nguồn đều được chọn ra: (//* | //@*). Từng phần XPath riêng cũng rất hữu dụng: nó chọn mọi thứ trừ nguyên bản trong tài liệu thông thường. Sau đó, một thuộc tính sẽ được áp dụng cho toàn bộ tập kết quả thông qua việc dùng dấu ngoặc đơn. Thuộc tính đó đầu tiên sẽ sử dụng hàm substring(): substring(name(), 1, 5). name() là một hàm mới, nó trả về tên của nút hiện tại sẽ được đánh giá. Do đó, một phần tử target sẽ trả về "target"; một thuộc tính classpath sẽ trả về "classpath." Cuối cùng, tên được trả về sẽ là một chuỗi con, chỉ có 5 ký tự đầu (có chỉ số từ 1 đến 5). Với "target," nó trả về trong "targe"; với "classpath," "class." Sau đó, giá trị này sẽ được so sánh với chuỗi "class". Bất cứ nút nào so khớp đều được thêm vào tập kết quả.

Hình 16 Chỉ ra kết quả. Về cơ bản, tất cả các phần tử và thuộc tính trong tài liệu đều bắt đầu bằng "class" và được trả về bởi XPath này.

Hình 16. Kiểm tra xem tên của một phần tử hoặc thuộc tính có bắt đầu bởi "class" không.
Kiểm tra xem tên của một phần tử hoặc thuộc tính có bắt đầu bởi class không

Đến đây, bạn đã biết được bản chất của các hàm. Để biết thêm thông tin về phần này, hãy tham khảo thêm tại địa chỉ trực tuyến (xem Tài nguyên), chứa tất cả các hàm trong XPath, cùng với cú pháp của nó. Chúng cũng khá sáng sủa, dễ hiểu khi bạn đã hoàn thành phần này và những phần còn lại của bài viết này.


So sánh nguyên bản của nút phần tử với các giá trị

Cho đến đây, chúng ta hầu như chỉ tập trung vào các giá trị thuộc tính, nhưng XML còn nhiều giá trị nguyên bản khác ngoài thuộc tính. Rõ ràng là các phần tử đều có nguyên bản của riêng nó và trong nhiều trường hợp, bạn có thể sử dụng chúng để so sánh, cũng giống như bạn làm với thuộc tính vậy.

Một tài liệu mẫu mới

Để thực hiện với các giá trị nguyên bản của các phần tử — cũng như với các thuộc tính nâng cao sẽ được thảo luận trong phần tiếp của bài viết, —bạn cần một tài liệu mẫu khác. File xerces-build.xml mà bạn đang sử dụng không có giá trị nguyên bản trong các phần tử, chúng chỉ là các phần tử rỗng với tất cả các dữ liệu nằm trong các thuộc tính.

Ví dụ 25 là một phần của vở kịch Shakespeare Macbeth dưới dạng XML. Như là với tệp xerces-build.xml, thực tế tệp này khá dài, tệp đầy đủ có tại Ví dụ 25 chỉ là một trích đoạn. Bạn có thể tải tệp, http://www.cafeconleche.org/examples/shakespeare/macbeth.xml, từ Tài nguyên của bài viết.

Ví dụ 25. Shakespeare's Macbeth trong định dạng XML
<?xml version="1.0"?>
<!DOCTYPE PLAY SYSTEM "play.dtd">

<PLAY>
<TITLE>The Tragedy of Macbeth</TITLE>

<FM>
<P>Text placed in the public domain by Moby Lexical Tools, 1992.</P>
<P>SGML markup by Jon Bosak, 1992-1994.</P>
<P>XML version by Jon Bosak, 1996-1998.</P>
<P>This work may be freely copied and distributed worldwide.</P>
</FM>

<PERSONAE>
<TITLE>Dramatis Personae</TITLE>

<PERSONA>DUNCAN, king of Scotland.</PERSONA>

<PGROUP>
<PERSONA>MALCOLM</PERSONA>
<PERSONA>DONALBAIN</PERSONA>
<GRPDESCR>his sons.</GRPDESCR>
</PGROUP>

<PGROUP>
<PERSONA>MACBETH</PERSONA>
<PERSONA>BANQUO</PERSONA>
<GRPDESCR>generals of the king's army.</GRPDESCR>
</PGROUP>

<PGROUP>
<PERSONA>MACDUFF</PERSONA>
<PERSONA>LENNOX</PERSONA>
<PERSONA>ROSS</PERSONA>
<PERSONA>MENTEITH</PERSONA>
<PERSONA>ANGUS</PERSONA>
<PERSONA>CAITHNESS</PERSONA>
<GRPDESCR>noblemen of Scotland.</GRPDESCR>
</PGROUP>

<PERSONA>FLEANCE, son to Banquo.</PERSONA>
<PERSONA>SIWARD, Earl of Northumberland, general of the 
   English forces.</PERSONA>
<PERSONA>YOUNG SIWARD, his son.</PERSONA>
<PERSONA>SEYTON, an officer attending on Macbeth.</PERSONA>
<PERSONA>Boy, son to Macduff. </PERSONA>
<PERSONA>An English Doctor. </PERSONA>
<PERSONA>A Scotch Doctor. </PERSONA>
<PERSONA>A Soldier.</PERSONA>
<PERSONA>A Porter.</PERSONA>
<PERSONA>An Old Man.</PERSONA>
<PERSONA>LADY MACBETH</PERSONA>
<PERSONA>LADY MACDUFF</PERSONA>
<PERSONA>Gentlewoman attending on Lady Macbeth. </PERSONA>
<PERSONA>HECATE</PERSONA>
<PERSONA>Three Witches.</PERSONA>
<PERSONA>Apparitions.</PERSONA>
<PERSONA>Lords, Gentlemen, Officers, Soldiers, Murderers, Attendants, and 
   Messengers. </PERSONA>
</PERSONAE>

<SCNDESCR>SCENE  Scotland: England.</SCNDESCR>

<PLAYSUBT>MACBETH</PLAYSUBT>

<ACT><TITLE>ACT I</TITLE>

<SCENE><TITLE>SCENE I.  A desert place.</TITLE>
<STAGEDIR>Thunder and lightning. Enter three Witches</STAGEDIR>

<SPEECH>
<SPEAKER>First Witch</SPEAKER>
<LINE>When shall we three meet again</LINE>
<LINE>In thunder, lightning, or in rain?</LINE>
</SPEECH>

<!-- LOTS more... -->

</SCENE>
</ACT>
</PLAY>

Chắc chắn rằng bạn đã sẵn sàng sử dụng tài liệu này. Sau khi bạn đẩy nó lên AquaPath hoặc Stylus Studio, thì bạn đã sẵn sàng để tiếp tục bài viết. Chú ý rằng ngoài tệp xerces-build.xml đã được nói đến ở trên, bài viết còn dùng tệp macbeth.xml. Hơn nữa, chú ý rằng tất cả tên các thành phần (element) trong tệp macbeth.xml đều viết hoa. Bởi vì XPath có phân biệt hoa, thường nên hãy chắc chắn rằng bạn đã chú ý đến việc viết hoa trong tài liệu của bài viết.

Bộ lọc dựa trên nguyên bản của các phần tử (element)

Để so sánh nguyên bản của phần tử với bất cứ cái gì, bạn cần lấy được nguyên bản của phần tử ra. Đây là việc mà trước đây bạn không phải làm, nhưng nó cũng đơn giản như việc lấy một thuộc tính thôi. Hàm text() trả về nguyên bản của một phần tử. Ví dụ 26 trả về tiêu đề của vở kịch, — trong trường hợp này là The Tragedy of Macbeth.

Ví dụ 26. Việc lấy về nguyên bản của một phần tử
/PLAY/TITLE/text()

Chắc chắn rằng bạn chọn window hoặc tab để lấy về nguyên bản. Bạn nên xem trong Hình 17.

Hình 17. Bạn có thể lấy được nguyên bản của một phần tử bằng cách sử dụng hàm text()
Hàm text() chọn nút nguyên bản của một element

Khi đã biết cách làm thế nào để lấy được nội dung nguyên bản của các phần tử rồi, bạn có thể sử dụng nó trong các thuộc tính (predicates) và các hàm so khớp khác, như trong Ví dụ 27.

Ví dụ 27. So sánh nội dung nguyên bản với một giá trị dạng ký tự
//*[contains(text(), 'Scotland')]

XPath này giới thiệu một hàm mới khác, hàm: contains(). contains() kiểm tra xem nếu đối số đầu tiên (chuỗi ký tự thứ nhất được đánh giá) có chứa giá trị của đối số thứ hai không (chuỗi ký tự thứ hai). Trong trường hợp này, XPath trong Ví dụ 27 kiểm tra tất cả các phần tử để xem các phần tử có chứa xâu ký tự 'Scotland' trong nội dung nguyên bản của nó không. Hình 18 hiển thị kết quả.

Hình 18. Hàm text() trong các khẳng định, làm việc rất tốt bên cạnh hàm contains()
Tất cả các phần tử với nguyên bản có chứa xâu ký tự 'Scotland' đều được trả về.

Nếu bạn sử dụng Stylus Studio, XPath này sẽ không làm việc và bạn sẽ bị báo lỗi. Hãy đọc thêm các đoạn tiếp theo, bạn sẽ giải thích được cụ thể điều gì đang xảy ra.

Chú ý rằng XPath này trả về các phần tử chứa nguyên bản nói trên. Nếu bạn muốn sử dụng nguyên bản riêng, hãy điều chỉnh một chút trong XPath, chẳng hạn như trong Ví dụ 28.

Ví dụ 28. Tham chiếu đến một nút nguyên bản bằng toán tử "."
//*/text()[contains(., 'Scotland')]

Giống như với các thuộc tính, toán tử tham chiếu tới nút hiện tại; trong trường hợp này, đó là nguyên bản của mỗi phần tử trong tài liệu.

Đây cũng là một cách nhắc tốt cho thấy bản thân nguyên bản trong một tài liệu cũng có thể chính là một nút hoặc một tập (collection) các nút. /PLAY/TITLE/text() vẫn đánh giá một tập các nút. Trong trường hợp này, nó sẽ đánh giá một nút đơn với giá trị là "The Tragedy of Macbeth." Tuy nhiên, nguyên bản được chứa trong một nút, như trong phần tử hoặc thuộc tính chẳng hạn.

XPath 1.0, XPath 2.0, và Stylus Studio

Nếu bạn đang sử dụng Stylus Studio trên nền Windows và đang cố thử đánh giá XPath trong Ví dụ 28, bạn có thể cũng nhận được một lỗi tương tự như trong Hình 19.

Hình 19. Stylus Studio hiển thị một lỗi liên quan đến việc sử dụng hàm contains()
Hàm contains() dường như là làm việc không liên tục trong Stylus Studio

Thực ra cũng chẳng có vấn đề gì cả. Nó chỉ đơn giản là sự không đồng nhất giữa phiên bản của XPath mà AquaPath cài đặt và Stylus Studio cài đặt mà thôi. Bài báo này được viết trên nền XPath 1.0, vì hầu hết các công cụ (tools) đều thực thi được với XPath 1.0. Tuy nhiên, Stylus Studio lại hiện đại hơn (xét về khía cạnh này) lại thực thi với XPath 2.0.

Trong XPath 2.0, bạn phải ứng dụng hàm contains() cho từng mục (item) đơn. Điều đó không có nghĩa là bạn không thể áp dụng hàm này cho nhiều nút, mà là bạn không thể sử dụng hàm contains() để đánh giá mọi nút mà nó là con của nút target chẳng hạn. Đây là một yêu cầu multinode, và hàm contains() trong XPath 2.0's không làm được việc đó.

XPath 2.0 có nhiều cách để hoàn thành những việc trên, nhưng nó nằm trong một cú pháp hoàn toàn mới và một trong số đó nằm trong các bài hướng viết khác. Nếu bạn quan tâm đến vấn đề này, hãy mail trực tiếp cho tôi hoặc tham gia thảo luận trong diễn đàn (liên kết nằm trong Tài nguyên).

Hầu hết các XPaths còn lại trong bài viết này đều làm việc với XPath 1.0 và 2.0, do đó, bạn sẽ không bị kẹt ở đây, không có vấn đề gì với hệ thống và công cụ bạn đang dùng cả.

Lấy ra nguyên bản con của nút phần tử hiện tại

Những điều thú vị thực sự bắt đầu khi bạn bắt đầu ứng dụng các vị ngữ tùy ý và kết hợp với các vị ngữ phức tạp hơn trong việc so khớp nguyên bản. Ví dụ, vở kịch Macbeth trình bày chi tiết ai là người đọc cho mỗi lời thoại. Thông thường thì tất cả các lời thoại đều do một diễn viên nói. Để làm được điều đó, bạn nên sử dụng một XPath giống như được đưa ra trong Ví dụ 29.

Ví dụ 29. Tham chiếu đến một nút nguyên bản với toán tử "."
//*/text()[contains(., 'Witch')]

Đó là điều quan tâm nhưng không phải là tất cả những thứ hữu ích. Cái gì sẽ là có ích, đó là tìm ra tất cả các hồi mà có một lời thoại được nói bởi các diễn viên. XPath này hơi phức tạp, nó được biểu diễn trong Ví dụ 30.

Ví dụ 30. Việc sử dụng các thuộc tính lồng nhau có chứa các thuộc tính con
//ACT[SCENE/SPEECH/SPEAKER[contains(text(), 'Witch')]]/TITLE/text()

Xem kết quả trong Hình 20. Sau đây, tôi sẽ chỉ cho bạn thấy chính xác điều gì đã xảy ra ở đây

Hình 20. Kết hợp các thuộc tính lồng nhau với hàm contains() và hàm text()
Tất cả các hồi (acts) với một lời thoại (speech) được nói bởi một diễn viên (witch) được trả về.

Đây là một trong những XPaths phức tạp nhất mà bạn từng thấy. Nhưng nếu bạn tách ra từng thứ một, bạn sẽ thấy nó cũng không có gì phức tạp cả

  1. Bộ đánh giá sẽ xác định tất cả các phần tử ACT (//ACT).
  2. Với mỗi ACT, bộ đánh giá áp dụng một vị từ dài ([SCENE/SPEECH/SPEAKER[contains(text(), 'Witch')]]). Có một số bước đã được cộng gộp ở đây:
    1. Việc điều hướng thông qua một phần tử lồng nhau SCENE, sau đó là các phần tử con SPEECH, sau đó là phần tử con SPEAKER của SPEECH (SCENE/SPEECH/SPEAKER).
    2. Với mỗi phần tử SPEAKER, xem xem giá trị nguyên bản có chứa chuỗi 'Witch' ([contains(text(), 'Witch')]).
    3. Nếu giá trị 'Witch' được tìm thấy, trả về true cho vị từ này.
  3. Các nút trả về trong các bước trên vẫn chỉ là phần tử ACT. Bộ đánh giá XPath tiếp tục bằng cách chọn TITLE của hồi kịch đó.
  4. Bộ đánh giá sẽ trả về giá trị nguyên bản của nút TITLE thông qua hàm text().

Không có việc đánh giá nào là quá khó khi ta sử dụng cách gỡ dần từng mức như đã làm. Chỉ cần làm cho XPath nhỏ hơn, từng bước một, bạn sẽ đánh giá được những XPaths phức tạp mà chẳng tốn nhiều thời gian.

Tuy vậy, dù cho có khả năng đơn giản hóa đi các XPath, còn một điều cần chú ý: Vị ngữ có thể lồng trong các vị ngữ khác. Trong Ví dụ 30, một vị từ nằm trong phần tử ACT chọn một vài mức lồng nhau. Tuy nhiên, cũng có một vị từ trong phần tử được chọn trong vị từ đầu tiên. Kết quả có một sự dư thừa nhỏ vì hai dấu ngoặc vuông (]]), bạn sẽ nhận thấy càng ngày XPath càng tăng độ phức tạp. Qui tắc đơn giản ở đây là: với mỗi tập nút, bạn có thể áp dụng một vị từ. Điều đó có nghĩa là, nếu bạn có một vị từ mà nó chọn được một tập các nút, bạn có thể áp dụng tập nút khác cho tập nút đó. Thường thì có hai vị ngữ, nhưng trong một số trường hợp có thể có tới ba hoặc bốn vị ngữ.

Giá trị của một phần tử là gì?

Trước khi bạn đi sâu vào nghiên cứu các chức năng nâng cao của XPath, bạn nên xử lý các vấn đề về nội dung hỗn hợp (mixed content). Nội dung hỗn hợp nghĩa là một phần tử có cả nội dung nguyên bản lẫn các phần tử lồng nhau. Điều này thường xuất hiện trong XHTML, và nó chính là "điều gây phiền nhiễu" cho các đặc tả kiểu XPath. Bởi vì, XPath hoặc là xử lý các phần tử lồng nhau, hoặc là xử lý nội dung nguyên bản, rất nhiều XPath và vị ngữ đòi hỏi sự khéo léo khi bạn bắt đầu làm việc với nội dung hỗn hợp, nếu bạn muốn nó hoạt động ổn định.

Bài toán trở về việc xử lý các nút. Hãy nhớ rằng, mọi thứ trong tài liệu (document) đều được coi như là một nút: các phần tử (element), các thuộc tính (attribute), và nguyên bản (text). Tuy nhiên, chẳng có thứ gì giống như một "nút hỗn hợp" mà lại chứa cả phần tử và text. Do đó, trong trường hợp nội dung hỗn hợp, cuối cùng thì bạn cũng sẽ làm việc với nhiều nút (multiple nodes) dưới các phần tử gốc: một nút cho mỗi phần tử con (child element), và một nút cho mỗi đoạn nguyên bản. Nếu một phần tử xuất hiện giữa hai bits của đoạn nguyên bản, bạn sẽ có nhiều hơn một nút nguyên bản. Bạn sẽ có một nút cho mỗi đoạn nguyên bản trước phần tử lồng nhau, một nút thành phần cho phần tử lồng nhau, và sau đó là nút nguyên bản khác các nguyên bản còn lại.

Giải pháp ngắn gọn nhất khi bạn làm việc với nội dung hỗn hợp là luôn viết XPath rõ ràng hết sức có thể và cẩn thận khi sử dụng hàm nào với —sự tin cậy đặc biệt — như text() chẳng hạn. Đây tuy không phải là một giải pháp đích thực, nhưng bạn sẽ phát hiện ra rằng trong nhiều trường hợp, bạn có thể tránh được phải làm việc với nội dung hỗn hợp (bằng việc lựa chọn và sử dụng các ràng buộc tốt trên XML) hoặc là nếu phải làm việc với nội dung hỗn hợp thì sẽ tránh phải dùng các hàm xử lý văn bản đặc biệt. Một tùy chọn hữu ích khác là làm ra các bộ lựa chọn (selections) sử dụng XPath, nhưng sau đó thì dùng các API hoặc chương trình khác để xử lý.


Sử dụng trục XPath (XPath axes) để điều hướng

Đâu đó khi làm việc với XPath, bạn sẽ gặp phải một tác giả tài liệu quan tâm đặc biệt đến các vị ngữ của bạn và hỏi rằng bạn sử dụng bao nhiêu trục tiền bối (ancestor axis), hoặc đề xuất rằng một hậu duệ (descendant) là một lựa chọn tốt hơn. Những thuật ngữ như: —trục (axis), tiền bối (ancestor), hậu duệ (hậu bối) (descendant), ...— tham chiếu cái được gọi là các trục tài liệu (document axes) trong XPath. Chúng là một phần quan trọng của XPath, và trong thực tế, không phải là mọi người đề cập đến hoặc sử dụng các thuật ngữ này đều tự phụ như chúng ta vừa nói ở trên. Tuy nhiên, trong nhiều trường hợp, bạn không cần đến các trục trong XPath.

Điều quan trọng là bạn phải hiểu được một nốt là gì thậm chí cả khi bạn chẳng bao giờ sử dụng nó một cách rõ ràng cả. Và cũng rất quan trọng khi bạn hiểu được các trục tài liệu trong XPath, kể cả khi bạn hiếm khi dùng nó, nó cũng góp phần củng cố thêm nền tảng về những thứ mà bạn đã và sẽ làm trong XPath.

Vậy một trục là gì?

Một trục tài liệu định nghĩa một tập nốt liên quan đến nốt hiện tại. Dù sao đi nữa, đó cũng chỉ là định nghĩa hình thức. Do đó, bạn có thể có một trục tài liệu đơn, hoặc bạn có thể nói về các tài liệu đa trục (multiple document axes). Và bạn có thể sử dụng những trục này.

Ví dụ, xem XPath sau:/PLAY/TITLE. Bạn có thể viết lại XPath này như trong Ví dụ 31.

Ví dụ 31. Sử dụng trục con (child axis)
/PLAY/child::node()[name()='TITLE']

XPath này đã sử dụng một trục con. child::node() trả về tất cả các nốt của con của tập nốt hiện tại (trong trường hợp này, tập nốt được chọn bởi /PLAY). Sau đó, XPath sử dụng một vị từ để chọn các tên của những nốt này và so sánh chúng với chuỗi ký tự 'TITLE'. Ví dụ 32 chỉ ra phiên bản đơn giản hơn của Ví dụ 31, mà vẫn sử dụng trục con.

Ví dụ 32. Sử dụng trục con (một mô hình trục con đơn giản)
/PLAY/child::TITLE

Tất nhiên không có cách dùng trục con nào lại đơn giản được bằng cách dùng /PLAY/TITLE, đó là lý do tại sao bạn thấy các trục tài liệu không được sử dụng thường xuyên.

Các trục tài liệu là vô hình

Mặc dù trục con không được sử dụng nhiều lắm, nó chỉ là cách mà XPath xây dựng câu lệnh của nó và là cách mà XPath đánh giá công việc của mình. Một XPath đơn lẻ bạn đều có thể viết ngắn gọn lại thành một tập các lệnh như sau:

axis::node-test[predicate]

Thường thì bạn bỏ qua trục và Xpath ngầm luận ra trục. Các trục ngầm đó thường trở thành child, chẳng hạn, /PLAY/TITLE thật ra là /PLAY/child::TITLE. Trong thực tế, bạn có thể dịch ra cho rõ ràng hơn: /child::PLAY/child::TITLE. Phần gạch chéo ban đầu chuyển thành gốc, sau đó là tên của child PLAY, tiếp sau là một child của child vừa rồi được đặt tên là TITLE.

Khi bạn làm việc với các thuộc tính, trục không chỉ được áp dụng như là một child mà còn là một thuộc tính. Do đó, quay trở lại tệp mẫu xerces-build.xml sample, xét XPath /project/target/@name. Bạn có thể hình dung việc sử dụng trục thuộc tính sẽ như trong Ví dụ 33.

Ví dụ 33. Sử dụng trục thuộc tính
/project/target/attribute::name

Tất nhiên bạn cũng có thể dịch thành Ví dụ 34 sử dụng cả các trục con và thuộc tính.

Ví dụ 34. Sử dụng trục con và trục thuộc tính
/child::project/child::target/attribute::name

Một lần nữa, XPath có thể làm được điều này trong nội tại bản thân nó, và không có lí do gì để bạn nghĩ đến những thuật ngữ này. Rõ ràng, /project/target/@name dễ dùng hơn.

Những trục có thể dùng được?

Bảng 1 liệt kê tất cả các trục có thể dùng được, mặc dù có thể bạn sẽ không bao giờ dùng nó trực tiếp.

Bảng 1. Các trục XPath
Document axisPurpose
selfChọn nốt hiện tại
parentChọn nốt cha của nốt hiện tại
childchọn tất cả con (children) của nốt hiện tại
attributeChọn tất cả các thuộc tính của nốt hiện tại
ancestor (hình thức nguyên thủy)Chọn tất cả các ancestors—parents, parents of parents, vân vân—của nốt hiện tại
ancestor-or-selfChọn các ancestors của nốt hiện tại cũng như bản thân nốt đó
descendant (hậu duệ)Chọn tất cả con, cháu, ...của nốt hiện tại
descendant-or-selfChọn tất cả các hậu duệ và bản thân nốt hiện tại
preceding (đằng trước)Chọn toàn bộ các nốt trong tài liệu mà nó xuất hiện trước nốt hiện tại
preceding-sibling (anh em liền trước) Chọn tất cả các nốt trong tài liệu mà là anh em —tại cùng một mức —của nốt hiện tại
following(theo sau) Chọn tất cả các nốt trong toàn bộ tài liệu mà xuất hiện sau nốt hiện tại
following-sibling(anh em liền sau)Chọn tất cả các nốt trong toàn bộ tài liệu là anh em —tại cùng một mức —của nốt hiện tại
namespaceChọn tất cả các nút không gian tên của nút hiện tại

Hầu hết các trục đều có tên gắn liền với chức năng của nó, và khá hữu ích khi biết về nó mặc dù có thể bạn không dùng nó trong thực hành XPaths.

Một số trục hữu ích

Một câu hỏi đặt ra là trục hữu ích khi nào? Các ứng dụng thường sinh ra các trục tài liệu khi bạn muốn làm nhiều hơn việc chỉ kiểm tra một phần tử con, hoặc một thuộc tính, hoặc chỉ một nút cha, trong những điều kiện nhất định nào đó. Ví dụ như khi bạn muốn tìm tất cả các (hồi, tiết mục) acts mà một witch (diễn viên) thực hiện chẳng hạn. Điều này cũng khá khó đấy, vì bạn sẽ phải kiểm tra tất cả các phần tử ACT cho các SPEECH ở nơi mà SPEAKER có chứa "Witch." Sau đó bạn cần kiểm tra tất cả các STAGEDIR phần tử trong những speeches để xem xem có một witch nào ra sân khấu nhưng lại không nói lời thoại không? Cuối cùng, bạn cũng muốn kiểm tra bản thân các LINE phần tử để xem có ai đó đề cập đến witch không? Đó là ba XPaths khác hẳn nhau, và điều tồi tệ nữa là: STAGEDIR có thể xuất hiện ngay cạnh bên ngoài một phần từSPEECH. Không phải một, mà là hai XPaths dành cho cho phần tửSTAGEDIR. Ví dụ 35 là cái thực sự bạn cần.

Ví dụ 35. Một XPath phức tạp (complex XPath) để chọn các giá trị từ các phần tử lồng nhau khác nhau
//ACT[SCENE/SPEECH/SPEAKER[contains(., 'Witch')]]/TITLE/text() |
  //ACT[SCENE/SPEECH/LINE[contains(., 'Witch')]]/TITLE/text() |
  //ACT[SCENE/SPEECH/STAGEDIR[contains(., 'Witch')]]/TITLE/text() |
  //ACT[SCENE/STAGEDIR[contains(., 'Witch')]]/TITLE/text()

Mặc dù với các trục, có một cách dễ hơn rất nhiều. Cái mà bạn thật sự muốn làm là kiểm tra mỗi phần tửACT để xem bất kỳ phần tử con có chứa từ "Witch" trong nó hay không. Đó là một ví dụ về việc sử dụng trục hậu bối (descendant axis), và bạn thử dùng nó với XPath trong Ví dụ 36.

Ví dụ 36. Dùng trục hậu bối để "nắm bắt được" tất của hậu duệ (con, cháu, ...) của một thành phần
//ACT[descendant::*[contains(., 'Witch')]]/TITLE/text()

Rõ ràng Ví dụ 36 là đơn giản hơn, dễ đọc hơn rất nhiều xong vẫn hiệu quả chẳng kém Ví dụ 35. Kết quả của Ví dụ 36 được hiển thị trong Hình 21.

Hình 21. Kiểm tra một vài phần tử hậu duệ (descendant elements) cho một giá trị kiểu chuỗi
descendant trả về tất cả các phần tử lồng nhau

Trong trường hợp này — bạn muốn tìm được những mức sâu hơn trong một phần tử, có thể là cho các phần tử khác nhau —mà các trục hướng tới.


Xây dựng SQL-like kết hợp với vị ngữ (predicates)

Cho đến đây, tất cả những vị ngữ mà bạn đã sử dụng để bắt được tập các nút hiện tại và xác định xem nút nào thuộc vào tập kết quả bằng cách so sánh một số thuộc tính hoặc phần tử con của các nút đặc biệt đó với một giá trị ký tự (literal value), hoặc xem xem nút đó có một child hoặc thuộc tính nào không. Đó là những việc mà bạn thường làm với XPath.

Tuy nhiên, đôi khi, cùng một mẩu dữ liệu lại được trình bày ở nhiều chỗ khác nhau trong cùng một tài liệu XML, hoặc hai mẩu dữ liệu có liên quan lại xuất hiện ở những phần khác nhau của cùng một tài liệu. Trong những trường hợp này, bạn có thể muốn liên kết những mẩu dữ liệu này lại trong một XPath. Nói cách khác, bạn muốn tạo ra một bộ chọn lọc (selection) trong một phần của tài liệu dựa trên dữ liệu có liên quan trong cả phần khác của tài liệu đó nữa. Đây chính là nơi XPath gặp phải các hạn chế, tuy không nhiều lắm. Với một vài XPaths thông minh, bạn có thể đạt được các kết nối SQL-like và kết nối các dữ liệu có liên quan, kể cả khi các mẩu dữ liệu bạn muốn liên kết nằm trong những phần hoàn toàn khác nhau của tài liệu XML.

Vị ngữ có thể điều hướng lên hoặc xuống hệ phân cấp XML

Để xử lý được các XPath phức tạp (complex XPaths) và khái niệm về việc kết hợp hai phần khác nhau của một tài liệu, bạn nhận ra rằng các vị từ luôn luôn có liên quan đến tập các nút có trước và bạn đã biết cách làm thế nào để chuyển một nút liên quan thành một nút thuần túy (absolute node): với một cái gạch chéo(single slash) (/). Bạn cũng đã biết làm thế nào để xác định được một phần tử nằm ở đâu trong một tài liệu: với hai cái gạch chéo (double slash) (//). Cả hai cách dùng slashes đều có thể xuất hiện ở đầu của vị ngữ.

Xem xét Ví dụ 37, nó là một phần của XPath ngớ ngẩn nhưng lại hoàn toàn hợp pháp.

Ví dụ 37. Sử dụng một vị từ với hai gạch chéo (double slash)
/PLAY/ACT[TITLE = //ACT/TITLE]

Đây là một sự tự tham chiếu cơ bản trong XPath hoặc là một đồng nhất thức. Xem xét kỹ hơn xem điều gì xảy ra ở đây:

  1. Bộ đánh giá sẽ xác định tất cả các ACT phần tử được lồng trong thành phần gốc PLAY.
  2. Phần tử TITLE của mỗi phần tử ACT được tham khảo trong vị từ. Bộ đánh giá (evaluator) so sánh phần tử TITLE đó với bất kỳ TITLE phần tử nào được lồng trong phần tử ACT trong bất cứ vị trí nào của tài liệu.
  3. Bởi vì mỗi nút được trả về bởi lệnh /PLAY/ACT/TITLE luôn luôn khớp với một nút được trả về từ //ACT/TITLE, nên vị từ luôn trả về giá trị true.

Bạn có thể nói rằng Ví dụ 37 cũng đơn giản như /PLAY/ACT.

Bạn có thể làm những điều tương tự với XPath trong Ví dụ 38.

Ví dụ 38. Sự so khớp dựa trên một giá trị trong một XPath khác.
/PLAY/ACT[TITLE = //TITLE[contains(., 'IV')]]/TITLE/text()

vị từ này chọn một TITLE có chứa xâu "IV" (chỉ được so khớp bởi tiêu đề "ACT IV") và sử dụng giá trị đó để so sánh đối chiếu ngược lại với tiêu đề TITLE của tập nút hiện tại. Một lần nữa đây là một ví dụ ngớ ngẩn và kém hiệu quả, sẽ đơn giản hơn nhiều nếu sử dụng XPath /PLAY/ACT/TITLE[contains(., 'IV')]/text() và bạn cũng có một XPath dễ đọc hơn. Tuy nhiên, khi bạn bắt đầu nghĩ về những vị ngữ sáng tạo kiểu như thế này, nó dẫn đến số khả năng đáng chú ý.

So sánh hai giá trị chưa xác định với vị ngữ

Xem qua phần đầu của tài liệu mẫu macbeth.xml. Có một số nhóm người trong các phần tử PGROUP, mỗi nhóm lại có một vài người: PERSONA, và một phần tử tùy chọn GRPDESCR với một đặc tả nhóm. Giả sử bạn muốn tất cả các lời thoại (speeches) mà người nói (speaker) nằm trong nhóm có đặc tả chứa cụm từ "Scotland." Đầu tiên, hãy luận ra XPath để lấy được về tất cả speakers mà không cần vị từ. XPath đó có thể là: //SPEECH/SPEAKER. Để thú vị hơn, chúng ta hãy tìm các lời thoại trong hồi II (speeches in Act II) và quay trở lại xem xét bản thân phần tử SPEECH thay vì phần tử SPEAKER. Bạn sẽ có một XPath như sau: //ACT[TITLE[contains(., 'ACT II')]]/SCENE/SPEECH. XPath này bỏ qua thành phần SPEAKER, nhưng bạn sẽ cần thành phần này khi bạn đạt đến vị từ.

Tiếp theo, hãy luận ra XPath bạn cần để chọn các người nói SPEAKERs với nhóm mà bạn muốn. Nó bao gồm một PGROUPGRPDESCR chứa cụm từ "Scotland," và sau đó với mỗi nhóm đó PGROUP, trả về tất cả phần tử người PERSONAs. Bạn có thể xem XPath hoàn thiện trong Ví dụ 39.

Ví dụ 39. Liên kết dữ liệu thông qua hai thứ chưa xác định trong một vị từ
//PGROUP[contains(GRPDESCR, 'Scotland')]/PERSONA

Thử chạy XPath này, bạn sẽ nhận được các nút giống như trong Hình 22.

Hình 22. Lấy về tất cả PERSONAs mà nằm trong một PGROUP nhất định
Việc xây dựng một XPath được sử dụng trong predicate

Giờ đây bạn có thể sử dụng XPath này như là một vế phải của một đẳng thức. Nói cách khác, bạn có thể so sánh nguyên bản của tất cả phần tử SPEAKER từ XPath đầu tiên với nguyên bản của tất cả các phần tử PERSONA được trả về trước đó. Ví dụ 40 là một XPath mà bạn nên sử dụng.

Ví dụ 40. Việc so khớp dựa trên một giá trị trong các XPath khác nhau
//ACT[TITLE[contains(., 'ACT II')]]/SCENE/SPEECH[SPEAKER/text() = 
  //PGROUP[contains(GRPDESCR, 'Scotland')]/PERSONA/text()]

Khi bạn đánh giá biểu thức này, hãy kiên nhẫn. Trên máy của tôi, AquaPath tốn khá nhiều thời gian. Đây là một XPath phức tạp và khá thú vị: Bạn đang chọn các nút trong một phần của tài liệu dựa trên những thông tin liên quan đến những phần khác của tài liệu. Điều thú vị ở đây là các nút có thể không liên quan đến nhau về mặt vị trí trong tài liệu hay trong sơ đồ phân cấp, nhưng lại liên quan đến nhau về mặt logic. Trên thực tế, trong tài liệu XML, chẳng có một mối liên hệ nào cả. Không có các phần tử hoặc thuộc tính được chia sẻ, và thậm chí tên của các thành phần phần tử trong mỗi phần cũng khác nhau. Tuy nhiên, bạn biết rằng các dữ liệu này là có liên quan đến nhau và đó mới là điều quan trọng.

Hãy tự chạy thử XPath này, bạn sẽ thấy kết quả giống như trong Hình 23.

Hình 23. Tìm ra tất cả lời thoại SPEECHes được nói bởi người nói SPEAKERs trong một nhóm PGROUP nhất định nào đó
Đây là một XPath phức tạp liên kết hai phần khác nhau của cùng một tài liệu XML trong cùng một bộ chọn lựa các nút

XPaths của bạn hiếm khi phải sử dụng thủ thuật này. Nếu bạn đã từng liên kết dữ liệu, việc bạn có thể kết nối các mẩu thông tin này thông qua một XPath quả là quí như vàng.


Kết luận

Giống như mọi loại đặc tả, XPath cũng chẳng có giá trị gì trừ khi bạn biết dùng nó như thế nào và dùng nó khi nào. XPath có thể làm được rất nhiều thứ, nhưng bạn sẽ chỉ thực sự thích nó và thấy được sự tiện lợi khi dùng nó một cách đúng đắn. Bạn phải dùng nó khi thích hợp và đừng dùng khi nó không phải là công cụ tốt nhất.

Vậy XPath lý tưởng nhất khi nào?

XPath là một công cụ tốt khi bạn muốn tìm thông tin đặc biệt trong một tài liệu XML. Không có một công cụ nào có thể nhanh bằng, nhạy cảm và hữu dụng bằng XPath khi bạn muốn tìm dữ liệu liên quan đến các phần tử, thuộc tính, hoặc dữ liệu nguyên bản, XPath cũng làm đơn giản hơn việc lọc ra những thành phần và thuộc tính mà bạn không mong muốn.

XPath là lý tưởng khi bạn đã nắm vững về cấu trúc của tài liệu XML. Có sự khác nhau rất lớn về hiệu quả của XPath /descendant-or-self::*[contains(., 'Fred')] và XPath //ACTOR[NAME[contains(., 'Fred')]]. XPath đầu tiên quả là rất tệ và sẽ không thể đoán trước được tốc độ xử lý sẽ thế nào khi ta đánh giá. Còn XPath thứ hai chứng tỏ sự hiểu cặn kẽ về cấu trúc của tài liệu nguồn và được xử lý và đánh giá một cách dễ dàng.

XPath không lý tưởng khi nào?

XPath đạt được những giá trị của nó khi bạn kết nối và tìm kiếm theo dạng SQL-like, như ta đã thảo luận trong , phần cuối cùng của bài viết này. Việc liên kết là có thể, và chẳng có gì sai ở đây cả, xong khi bạn đã đạt đến mức tinh tế trong việc sử dụng XPath, bạn lại thích khảo sát XQuery hơn. XQuery xây dựng trên XPath để cho phép bạn đặt hàng (ordering), thậm chí là định nghĩa lại các tiêu chuẩn lựa chọn, và có thể xử lý mỗi giá trị trả về trọn vẹn hơn XPath có thể làm.

XPath cũng chỉ là một bộ chuyển đổi và xử lý đặc tả. Nó không thân thiện với việc phối hợp văn bản, chèn dữ liệu và trong một chuỗi ký tự, thêm vào nút các giá trị, hay bất cứ thứ gì ngoài việc lựa chọn. XSLT xây dựng trên XPath, và cả XQuery có thể làm một số định dạng cho bạn. Ngoài ra, bạn còn có thể sử dụng Java or C# (hoặc một ngôn ngữ lập trình nào đó) API đưa vào các kết quả của XPath và xử lý chúng bằng ngôn ngữ lập trình. Hãy xem các bài viết trong tương lai của IBM developerWorks để biết thêm về những điều này.

Tôi nên tiếp tục ở đâu?

Điều tốt nhất mà bạn có thể làm là sử dụng XPath trong chính ứng dụng của mình ngay tức thì. Tốt nhất là làm khoảng 30 đến 40 ví dụ trong một tệp hoặc làm thêm cho vở kịch Shakespeare. Không có gì hiệu quả bằng việc thử XPath trong chính các tài liệu của mình, bạn sẽ biết được tài liệu chứa cái gì trong đó, và bạn sẽ thấy hài lòng khi thoát được những khó khăn trong việc tìm được đến những nút mình muốn khi bạn lập trình.

Bạn cũng nên xem qua những ứng dụng đã có xem họ đặt những XPath phù hợp với ứng dụng của mình ở đâu. Tìm kiếm cơ hội để sử dụng những gì bạn đã học được trong bài viết thứ hai này.

Khi bạn đã nắm được XPath trong tầm tay, hãy làm theo một trong hai cách (hoặc cả hai) sau:

  1. Học cách sử dụng XPath với ngôn ngữ lập trình mà bạn yêu thích: Những bài báo trên IBM developerWorks về việc sử dụng XPath trong Java, cũng như XQuery trong Java. Đây là nơi rất tốt để bạn củng cố thêm kiến thức về XPath và biết cách kết hợp nó vào trong môi trường lập trình.
  2. Học XQuery và/hoặc XSLT: Cả hai công cụ đặc tả XML được xây dựng trên nền XPath và cho bạn nhiều khả năng hơn. Bạn vừa có thể củng cố thêm kiến thức về XML, vừa học thêm được những thủ thuật hay.

Dù làm gì đi nữa, hãy thử đưa XPath vào ứng dụng hiện tại của mình. Bạn sẽ quen thuộc hơn với những khái niệm như vị ngữ, các trục, và biết được XPath thực sự có thể làm được gì. Và hi vọng rằng, các ứng dụng của bạn sẽ được cải tiến và mềm dẻo hơn, và rằng, XML sẽ là một dạng tài liệu được sử dụng nhiều hơn.


Tải về

Mô tảTênKích thước
Ví dụ mã nguồnx-introxpath2.zip58KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

  • Stylus Studio 2008 XML: Tải về để bắt đầu làm việc với XPath và các tài liệu XML trên nền hệ điều hành Windows.
  • AquaPath: Tải về để dễ dàng làm việc với XPath trên hệ điều hành Mac OS X.
  • Scandalous Software: Kiểm tra tập hợp các công cụ liên quan đến XML, tất cả được áp dụng cho hệ điều hành Mac OS X.
  • Java & XML, Third Edition (Brett McLaughlin and Justin Edelson, O'Reilly Media, 2006): Làm việc đầy đủ với XML từ đầu đến cuối bao gồm thông tin mở rộng dựa trên các từ vựng khác nhau của XML.
  • IBM trial software for product evaluation (Phần mềm dùng thử IBM để đánh giá sản phẩm): Dùng để xây dựng dự án tiếp theo bằng phần mềm dùng thử được tải trực tiếp từ developerWorks, bao gồm các công cụ phát triển ứng dụng và các sản phẩm trung gian từ DB2®, Lotus®, Rational®, Tivoli®, và WebSphere®.

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở, Công nghệ Java
ArticleID=387545
ArticleTitle=Định vị các phần cụ thể của tài liệu XML với XPath, Phần 2
publish-date=06172008