Mô hình Đối tượng Tài liệu (viết tắt là DOM) thậm chí xuất hiện trước cả XML. DOM cho phép một người phát triển tham chiếu, truy lục, và thay đổi các mục trong một cấu trúc XML, và nó cũng đóng một vai trò quan trọng đối với XML. Trong hướng dẫn này, bạn sẽ nghiên cứu về cấu trúc của một tài liệu DOM. Bạn cũng sẽ nghiên cứu cách sử dụng công nghệ Java™ để tạo ra một Tài liệu từ một tệp XML, thay đổi nó, và truy lục đầu ra.

Nicholas Chase, Tác giả tự do, Site Dynamics Interactive Communications

Nicholas Chase đã phát triển trang web cho các công ty lớn như Lucent Technologies, Sun Microsystems, Oracle, và Tampa Bay Buccaneers. Nick đã từng là một giáo viên vật lý ở trường phổ thông, một nhà quản lý thiết bị phóng xạ mức thấp, một nhà biên tập tạp chí khoa học viễn tưởng trực tuyến, một kỹ sư đa phương tiện, một hướng dẫn của Oracle, và một trưởng phòng công nghệ của một công ty tương tác truyền thông. Nick là tác giả của một số sách



12 03 2007 (Xuất bản lần đầu tiên vào ngày 17 07 2009)

Lời giới thiệu

Ai nên đọc hướng dẫn này?

Hướng dẫn này được thiết kế dành cho những người phát triển đã hiểu những khái niệm cơ bản về XML và sẵn sàng với các ứng dụng mã trình để chế tác XML bằng cách sử dụng Mô hình Đối tượng Tài liệu (DOM). Hướng dẫn này mặc định rằng bạn đã biết các khái niệm như là sự tổ chức tốt và bản chất thẻ của một tài liệu XML. (Bạn có thể tìm thấy khái niệm cơ bản về XML qua bài hướng dẫn Giới thiệu về XML.)

Tất cả các ví dụ trong hướng dẫn này được viết bằng ngôn ngữ Java, nhưng bạn có thể phát triển các ví dụ của riêng bạn thông qua sự hiểu rõ về DOM. Các khái niệm và API để mã hóa một ứng dụng chế tác dữ liệu XML trong DOM đối với các ngôn ngữ hay nền tảng khác nhau, là hoàn toàn tương tự. Lập trình GUI không được đề cập ở đây.

Mô hình Đối tượng Tài liệu là gì?

Nền tảng của Ngôn ngữ Đánh dấu Mở rộng (XML) là DOM. Các tài liệu XML có một hệ đẳng cấp của các đơn vị thông tin được gọi là các nút; DOM là một cách để miêu tả các nút đó và những mối quan hệ giữa chúng.

Với vai trò như một mô tả khái niệm của dữ liệu XML, DOM là một loạt các Đề nghị được duy trì bởi Tổ chức chuẩn Web Quốc tế (W3C). DOM đầu tiên được sử dụng như một cách để giúp các trình duyệt nhận dạng và chế tác các phần tử trên một trang -- tính năng có trước khi có sự liên quan của W3C và được coi như là "DOM Mức 0".

Đề nghị DOM hiện đang ở Mức 2, nó là một API xác định các đối tượng có trong một tài liệu XML, cũng như các phương pháp và các đặc tính được sử dụng để truy cập và chế tác chúng.

Hướng dẫn này giải thích tiện ích của DOM Lõi API như một phương tiện để đọc và chế tác dữ liệu XML bằng việc sử dụng ví dụ của một loạt các đơn đặt hàng từ một hệ thống thương mại. Nó cũng hướng dẫn bạn cách tạo ra các đối tượng DOM trong các dự án riêng của bạn để lưu trữ hoặc làm việc với dữ liệu.

Các công cụ

Nếu bạn muốn chạy các ví dụ trong hướng dẫn này một cách chính xác như hướng dẫn, máy tính của bạn cần được cài đặt các công cụ dưới đây. Việc chạy các ví dụ này không phải là một yêu cầu cần phải hiểu

  • Một trình biên tập văn bản: Các tệp XML là các văn bản đơn giản. Để tạo ra và đọc chúng, bạn cần có một trình biên tập văn bản.
  • Java™ 2 SDK, Standard Edition version 1.4.x: Hỗ trợ DOM đã được xây dựng trong phiên bản mới nhất của công nghệ Java (có tại địa chỉ http://java.sun.com/j2se/1.4.2/download.html), nên bạn sẽ không cần cài đặt thêm bất cứ lớp tách rời nào. (Nếu bạn đang sử dụng một phiên bản cũ của ngôn ngữ Java như là Java 1.3.x, bạn sẽ cần có thêm một trình phân tích XML như Xerces-Java của dự án Apache (có tại địa chỉ http://xml.apache.org/xerces2-j/index.html), hoặc Java API của Sun dành cho Phân tích XML (JAXP), nó là một phần của Java Web Services Developer Pack (có tại địa chỉ http://java.sun.com/webservices/downloads/webservicespack.html).
  • Các Ngôn ngữ khác: Nếu bạn muốn phỏng theo các ví dụ, các thực thi DOM cũng được sử dụng trong các ngôn ngữ lập trình khác. Bạn có thể tải xuống các thực thi C++ và Perl của trình phân tích Xerces từ Dự án Apache tại http://xml.apache.org.

DOM là gì?

Cấu trúc của DOM

Trước khi bắt đầu làm việc với DOM, chúng ta cần hình dung thực sự DOM là gì. Một DOM Document là một tập của các nút, hay những mẩu thông tin, được tổ chức trong một hệ phân cấp. Hệ phân cấp này cho phép một người phát triển điều hướng quanh biểu đồ hình cây để tìm kiếm thông tin cụ thể. Phân tích cấu trúc thường đòi hỏi toàn bộ tài liệu phải được nạp và hệ phân cấp cần được xây dựng trước khi công việc được hoàn thành. Bởi vì nó được dựa trên một hệ phân cấp của thông tin, DOM có thể được gọi là dựa trên biểu đồ cây, hay dựa trên đối tượng.

Đối với các tài liệu tương đối lớn, việc phân tích và nạp toàn bộ tài liệu có thể rất chậm và chiếm nhiều tài nguyên, nên các phương tiện khác sẽ tốt hơn khi làm việc với dữ liệu này. Những mô hình dựa trên sự kiện, như là API Đơn giản dành cho XML (SAX), sẽ làm việc trên luồng của dữ liệu bằng cách xử lý dữ liệu khi nó đi qua. (SAX là chủ đề của một hướng dẫn và nhiều bài viết khác trên vùng developerWorks XML. Xem Tài nguyên để biết thêm thông tin chi tiết.) Một API dựa trên sự kiện không cần phải xây dựng cây dữ liệu trong bộ nhớ, nhưng nó không cho phép một người phát triển thay đổi dữ liệu trong tài liệu gốc.

Theo cách khác, DOM cũng cung cấp một API cho phép một người phát triển thêm, sửa, di chuyển, hay xóa các nút tại bất cứ vị trí nào trên cây dữ liệu để tạo ra một ứng dụng.

Lộ trình DOM

Làm việc với DOM bao gồm một số khái niệm có liên quan đến nhau. Bạn sẽ nghiên cứu về những mối quan hệ đó trong hướng dẫn này.

Một trình phân tích là một ứng dụng phần mềm được thiết kế để phân tích một tài liệu -- trong trường hợp này, nó là một tệp XML -- và làm một số việc cụ thể với thông tin. Trong một API dựa trên sự kiện như SAX, trình phân tích gửi các sự kiện tới một trình lắng nghe của một số phân loại. Trong một API dựa trên biểu đồ hình cây như DOM, trình phân tích xây dựng một cây dữ liệu trong bộ nhớ.

DOM với chức năng như một API

Bắt đầu với DOM Mức 1, DOM API chứa các giao diện biểu thị tất cả các kiểu thông tin khác nhau có thể được tìm thấy trong một tài liệu XML, như là các phần tử và văn bản. Nó cũng bao gồm các phương pháp và các đặc tính cần thiết để làm việc với các đối tượng này.

Mức 1 hỗ trợ đối với XML 1.0 và HTML, với mỗi phần tử HTML được miêu tả như một giao diện. Nó cũng bao gồm các phương pháp để thêm, sửa, di chuyển, và đọc thông tin chứa trong các nút. Mặc dù vậy, nó không hỗ trợ đối với các Không gian tên XML (XML namespace) cung cấp khả năng phân đoạn thông tin trong một tài liệu.

Hỗ trợ Không gian tên được thêm vào DOM Mức 2. Mức 2 mở rộng hơn Mức 1, nó cho phép những người phát triển tìm và sử dụng thông tin không gian tên có thể áp dụng cho một nút. Mức 2 cũng thêm một số mô đun mới có hỗ trợ các Bảng Định kiểu phân lớp CSS, các sự kiện, và các thao tác biểu mẫu hình cây được cải thiện.

DOM Mức 3, hiện tại sắp được hoàn thành, sẽ hỗ trợ tốt hơn trong việc tạo ra một đối tượng Document (các phiên bản trước để điều này tùy thuộc vào thực thi, điều này đã gây khó khăn trong việc tạo các ứng dụng có đặc điểm chung), hỗ trợ Không gian tên được cải thiện, và hỗ trợ các mô đun mới để nạp và lưu các tài liệu, phê chuẩn, và XPath, phương tiện để lựa chọn các nút được sử dụng trong các Chuyển đổi XSL và các công nghệ XML khác.

Sự mô đun hóa DOM có nghĩa là khi bạn là một người phát triển, bạn phải biết liệu các tính năng bạn định sử dụng có được hỗ trợ bởi thực thi DOM mà bạn đang làm việc hay không.

Xác định hiệu lực của tính năng

Tính chất mô đun của các Giới thiệu DOM cho phép những người thực thi xem xét và lựa chọn phần nào sẽ bao gồm trong sản phẩm của họ, nên nó có thể cần thiết phải quyết định liệu một tính năng cụ thể được tạo ra trước khi cố gắng sử dụng nó hay không. Hướng dẫn này chỉ sử dụng Lõi API DOM Mức 2, nhưng nó giúp bạn hiểu cách các tính năng có thể được tìm thấy khi di chuyển trong các dự án riêng của bạn.

Một trong các giao diện được xác định trong DOM là DOMImplementation. Bằng việc sử dụng phương pháp hasFeature(), bạn có thể quyết định một tính năng cụ thể có được hỗ trợ hay không. Không có tiêu chuẩn cho việc tạo ra một DOMImplementation trong DOM Mức 2, nhưng mã trình dưới đây sẽ hướng dẫn cách sử dụng hasFeature() để quyết định liệu mô đun các Tập tin Theo kiểu DOM Mức 2 có được hỗ trợ trong một ứng dụng Java hay không.

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.DOMImplementation;

public class ShowDomImpl {
	
   public static void main (String args[]) {
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder docb = dbf.newDocumentBuilder();
         DOMImplementation domImpl = docb.getDOMImplementation();
	
         if ( domImpl.hasFeature("StyleSheets", "2.0") ) {
            System.out.println("Style Sheets are supported.");
         } else {
            System.out.println("Style Sheets are not supported.");
         }
      } catch (Exception e) {}				  
	}
	
}

(DOM Mức 3 sẽ bao gồm một phương tiện chuẩn dành cho việc tạo ra một DOMImplementation.)

Hướng dẫn này sử dụng một tài liệu đơn lẻ để giải thích các đối tượng và các phương pháp của Lõi API DOM Mức 2.

Tệp XML cơ bản

Các ví dụ trong hướng dẫn này sử dụng một tệp XML chứa ví dụ mã trình bên dưới, nó cho biết cách các đơn đặt hàng được xử lý trong một hệ thống thương mại. Về tổng quan, các phần cơ bản của tệp XML bao gồm:

  • Khai báo XML: Khai báo cơ bản <?xml version"1.0"?> xác định tệp này như là một tài liệu XML. Nó ít khi chỉ định một mã hóa trong khai báo, như hiển thị bên dưới. Theo cách này, trình phân tích có thể đọc các tài liệu XML, cho dù tệp XML sử dụng bất cứ ngôn ngữ hay mã hóa nào, nhưng với điều kiện trình phân tích phải hiểu được các mã hóa đó.
  • Khai báo DOCTYPE: XML là một cách thuận tiện để trao đổi thông tin giữa con người và các thiết bị máy móc, nhưng để nó hoạt động trơn tru, cần thiết phải có một bảng từ vựng chung. Tuyên bố tùy chọn DOCTYPE có thể được sử dụng để chỉ định một tài liệu -- trong trường hợp này, nó là orders.dtd -- để so sánh với tệp này nhằm đảm bảo không xảy ra sự thất lạc hay thiếu thông tin (ví dụ, một userid bị thiếu hay tên phần tử bị sai chính tả). Những tài liệu được xử lý theo cách này được coi như là các tài liệu hợp lệ. Sự phê chuẩn thành công không cần thiết đối với XML, và tôi sẽ đề cập về tuyên bố DOCTYPE trong các ví dụ của các phần tiếp theo.
  • Dữ liệu: Dữ liệu trong một tài liệu XML phải được chứa trong một phần tử gốc đơn lẻ, như là phần tử orders dưới đây. Đối với một tài liệu XML sắp được xử lý, nó phải được tổ chức tốt.
 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ORDERS SYSTEM "orders.dtd"> <orders> 
   <order>
      <customerid limit="1000">12341</customerid>
      <status>pending</status>
      <item instock="Y" itemid="SA15">
         <name>Silver Show Saddle, 16 inch</name>
         <price>825.00</price>
         <qty>1</qty>
      </item>
      <item instock="N" itemid="C49">
         <name>Premium Cinch</name>
         <price>49.00</price>
         <qty>1</qty>
      </item>
   </order>
   <order>
      <customerid limit="150">251222</customerid>
      <status>pending</status>
      <item instock="Y" itemid="WB78">
         <name>Winter Blanket (78 inch)</name>
         <price>20</price>
         <qty>10</qty>
      </item>
   </order>
 </orders> 

Trong DOM, khi làm việc với thông tin XML, việc đầu tiên là phải ngắt nó thành các nút.


Các kiểu nút khác nhau của XML

Tạo hệ phân cấp

Về bản chất, DOM là một tập hợp của các nút. Với các kiểu thông tin khác nhau có thể được chứa trong một tài liệu, một số kiểu nút được xác định.

Trong việc tạo ra một hệ phân cấp dành cho một tệp XML, nó sẽ cơ bản sinh ra các nút như cấu trúc dưới đây. Nó là một miêu tả chính xác của dữ liệu được bao gồm, nhưng nó không phải là một mô tả chính xác của dữ liệu như miêu tả bởi DOM. Điều này là bởi vì nó chỉ miêu tả các phần tử, nhưng không miêu tả các nút.

Sự khác nhau giữa các phần tử và các nút

Trên thực tế, các phần tử chỉ là một loại của nút, và chúng thậm chí không miêu tả những gì mà sơ đồ trước đây đã chỉ ra. Một nút phần tử là một trình chứa cho thông tin. Thông tin đó có thể là các nút phần tử, nút văn bản, nút thuộc tính, hay các loại khác của thông tin. Hình chính xác hơn của tài liệu được biểu thị như dưới đây:

Những hình hộp chữ nhật tương ứng với các nút phần tử, và các hình bầu dục tương ứng với các nút văn bản. Khi một nút được chứa trong một nút khác, nó được xem như là một nút con của nút đó.

Chú ý rằng nút phần tử orders không phải có hai, mà là năm nút con: hai phần tử order, và các nút văn bản giữa và xung quanh chúng. Mặc dù nó không có nội dung, ký tự trắng giữa các phần tử order tạo ra một nút văn bản. Tương tự, item có bảy nút con: name, price, qty, và bốn nút văn bản xung quanh chúng.

Cũng chú ý rằng những gì có thể được coi là nội dung của một phần tử, như "Premium Cinch", thực chất là nội dung của một nút văn bản là nút con của phần tử name.

(Sơ đồ này chưa đầy đủ vì nó thiếu các nút thuộc tính.)

Những loại nút cơ bản: tài liệu, phần tử, thuộc tính, và văn bản

Những loại nút phổ biến trong XML là:

  • Các phần tử: Các phần tử là các khối xây dựng cơ bản của XML. Đặc biệt, các phần tử có các nút con là các nút phần tử, và văn bản khác, hay một kết hợp của cả hai nút này. Các nút phần tử cũng chỉ là một loại nút có thể có các thuộc tính.
  • Các thuộc tính: Các nút thuộc tính chứa thông tin về một nút phần tử, nhưng không thực sự được coi như là nút con của phần tử, như trong:
     <customerid  limit="1000" 
    >12341</customerid>
  • Văn bản: Một nút văn bản chính xác là -- văn bản đó. Nó có thể bao gồm nhiều thông tin hay chỉ là ký tự trắng.
  • Tài liệu: nút tài liệu là nút cha cho tất cả các nút khác trong tài liệu.

Những loại nút ít phổ biến hơn: CDATA, chú thích, các lệnh xử lý, và các mẩu tài liệu

Các loại nút khác được sử dụng ít thường xuyên hơn, nhưng chúng vẫn có vai trò quan trọng trong một số hoàn cảnh. Các loại nút này bao gồm:

  • CDATA: là viết tắt của Dữ liệu Ký tự, nó là một nút chứa thông tin không được phân tích bởi trình phân tích. Thay vào đó, nó nên được thông qua như văn bản đơn giản. Ví dụ, HTML có thể được lưu trữ theo một mục đích cụ thể. Trong những tình huống bình thường, bộ xử lý có thể tạo ra các phần tử cho mỗi thẻ được lưu trữ, những thẻ này có thể không được tổ chức tốt. Những vấn đề này có thể tránh được bằng cách sử dụng các bộ phận CDATA. Những bộ phận này được viết với một chú thích đặc biệt:
     <[CDATA[ <b>
    Quan trọng:  Chú ý không thò đầu và tay ra ngoài khi đi xe tại <i
    >bất kỳ thời điểm nào</i>.
    </b> ]]>
  • Chú thích: Các chú thích bao gồm các thông tin về dữ liệu, và nó thường xuyên bị bỏ qua bởi ứng dụng. Chúng được viết như dưới đây:
     <!-- Đây là một chú thích.  -->
  • Các Lệnh Xử lý: Lệnh xử lý là thông tin có mục đích cụ thể tại ứng dụng. Một số ví dụ là mã trình sẽ được thi hành hay các thông tin trên đó để tìm một tranh định dạng. Ví dụ:
     <? xml-stylesheet type="text/xsl" href="foo.xsl"? >
  • Các Mẩu Tài liệu: Nếu được tổ chức tốt, một tài liệu có thể chỉ có một phần tử gốc. Thỉnh thoảng, trong khi làm việc với XML, các nhóm phần tử có thể được tạm thời tạo ra nên không cần thiết phải đáp ứng yêu cầu này. Một mẩu tài liệu có thể được thấy như dưới đây:
     <item instock="Y" itemid="SA15">
             <name>Silver Show Saddle, 16 inch</name>
             <price>825.00</price>
             <qty>1</qty>
          </item>
          <item instock="N" itemid="C49">
             <name>Premium Cinch</name>
             <price>49.00</price>
             <qty>1</qty>
          </item>

Các loại khác của nút bao gồm các thực thể, các nút tham chiếu thực thể, và các ký hiệu.

Để tổ chức dữ liệu XML tốt hơn, bạn có thể sử dụng các không gian tên.


Các không gian tên

Không gian tên là gì?

Một trong những cải tiến chính của DOM Mức 2 so với DOM Mức 1 là nó có thêm khả năng hỗ trợ dành cho cáckhông gian tên. Hỗ trợ không gian tên cho phép những người phát triển sử dụng thông tin từ các nguồn khác nhau hay với nhiều mục đích khác nhau mà không bị các xung đột.

Các không gian tên là các vùng khái niệm mà ở đó tất cả các tên phải là duy nhất.

Ví dụ, tôi đã từng làm việc trong một văn phòng và ở đó tên của tôi trùng với tên của một khách hàng. Nếu tôi ở văn phòng và nhân viên lễ tân thông báo "Nick, có điện thoại ở đường dây số 1", tất cả mọi người đều biết nhân viên lễ tân đó gọi tôi, bởi vì tôi đã ở trong "không gian tên của văn phòng". Tương tự, nếu nhân viên lễ tân thông báo "Nick đang ở đường dây số 1," tất cả mọi người đều biết đó là khách hàng, bởi vì người gọi không có trong không gian tên của văn phòng.

Trong trường hợp khác, nếu tôi rời khỏi văn phòng và người lễ tân cũng thực hiện một thông báo tương tự, sự nhầm lẫn có thể xảy ra bởi vì sẽ có hai không gian tên giống nhau tồn tại.

Những vấn đề phát sinh tương tự xuất hiện khi dữ liệu XML được kết hợp từ các nguồn khác nhau (như là thông tin đánh giá mức độ tín nhiệm trong tệp mẫu sẽ được trình bày chi tiết trong phần sau của hướng dẫn này).

Tạo một không gian tên

Bởi vì những trình định danh dành cho các không gian tên phải là duy nhất, nên chúng được định rõ bằng các Định danh Tài Nguyên Thống nhất (URIs). Ví dụ, một không gian tên mặc định dành cho dữ liệu mẫu sẽ được định rõ bằng việc sử dụng thuộc tính xmlns:

 <?xml version="1.0" encoding="UTF-8"?>
<orders  xmlns="http://www.nicholaschase.com/orderSystem.html" >
     <order>
      <customerid limit="1000">12341<customerid>
...
</orders>

(... cho biết những bộ phận không liên quan.)

Bất cứ phần tử nào không có một không gian tên sẽ được nằm trong không gian tên mặc định, http://www.nicholaschase.com/orderSystem.html. Thực chất bản thân URI không có nghĩa. Thông tin có thể hoặc không ở địa chỉ đó, nhưng điều quan trọng nhất là nó phải duy nhất.

Đặc biệt chú ý sự khác nhau rất lớn giữa không gian tên mặc định và việc không có không gian tên. Trong trường hợp này, các phần tử không có tiền tố không gian tên sẽ nằm trong không gian tên mặc định. Trước đây, khi không có không gian tên mặc định tồn tại, những phần tử đó nằm trong phần không có không gian tên.

Bạn cũng có thể tạo ra các không gian tên thứ cấp, và thêm các phần tử và các thuộc tính vào các không gian tên đó.

Định rõ các không gian tên

Các không gian tên khác cũng có thể được định rõ dành cho dữ liệu. Ví dụ, bằng việc tạo một không gian tên rating bạn có thể thêm thông tin về mức độ đánh giá tín nhiệm vào văn bản của các đơn đặt hàng mà không xáo trộn dữ liệu hiện thời.

Không gian tên thường được tạo ra cùng với một bí danh trên phần tử gốc của tài liệu. Bí danh này được sử dụng như là một tiền tố cho các phần tử và các thuộc tính -- nếu cần thiết, khi có hơn một không gian tên đang sử dụng -- để chỉ định không gian tên chính xác.

Hãy xem mã trình dưới đây. Không gian tên và bí danh rating đã được sử dụng để tạo ra phần tử creditRating.

 <?xml version="1.0" encoding="UTF-8"?>
<orders xmlns="http://www.nicholaschase.com/orderSystem.html"
       xmlns:rating="http://www.nicholaschase.com/rating.html" >
   <order>
      <customerid limit="1000">
         12341
         < rating: creditRating>good</ rating: creditRating>
      </customerid>
      <status>
         pending
      </status>
      <item instock="Y" itemid="SA15">
         <name>
            Silver Show Saddle, 16 inch
         </name>
         <price>
            825.00
         </price>
         <qty>
            1
         </qty>
      </item>
   ...
</orders>

Thông tin không gian tên có thể được sử dụng cho một nút sau khi tài liệu được phân tích xong.


Phân tích một tệp vào trong một tài liệu

Quá trình ba bước

Để làm việc với thông tin trong một tệp XML, thì tệp phải được phân tích để tạo ra một đối tượng Document.

Đối tượng Document là một giao diện, nên nó không thể được minh họa một cách trực tiếp. Quá trình chính xác thay đổi từ thực thi này đến thực thi khác, nhưng bản chất vẫn giống nhau. (Mức 3 sẽ tiêu chuẩn hóa nhiệm vụ này). Trong môi trường Java ví dụ, phân tích tệp là một quy trình gồm ba bước:

  1. Tạo DocumentBuilderFactory. Đối tượng này tạo ra DocumentBuilder.
  2. Tạo DocumentBuilder.DocumentBuilder thực hiện phân tích hiện thời để tạo ra đối tượng Document.
  3. Phân tích tệp để tạo ra đối tượng Document.

Bây giờ bạn có thể bắt đầu xây dựng ứng dụng.

Ứng dụng cơ bản

Bắt đầu bằng việc tạo ra ứng dụng cơ bản, một lớp được gọi là OrderProcessor.

 import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import org.w3c.dom.Document;

public class OrderProcessor {
   public static void main (String args[]) {
      File docFile = new File("orders.xml");
      Document doc = null;      
      try {
 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
DocumentBuilder db = dbf.newDocumentBuilder(); doc = db.parse(docFile); 
      } catch (Exception e) {
         System.out.print("Problem parsing the file: "+e.getMessage());
      }
   }
}

Đầu tiên, mã trình Java nạp vào các lớp cần thiết, và sau đó nó tạo ra ứng dụng OrderProcessor. Những ví dụ trong hướng dẫn này sử dụng một tệp, để đơn giản, ứng dụng sẽ chứa một tham chiếu trực tiếp đến nó.

Do vậy đối tượng Document có thể được sử dụng sau đó, ứng dụng xác định nó bên ngoài khối try-catch.

Trong khối try-catch, ứng dụng tạo ra DocumentBuilderFactory sau đó được sử dụng để tạo ra DocumentBuilder. Cuối cùng , DocumentBuilder phân tích tệp để tạo ra Document.

Các thiết lập trình phân tích

Một trong những ưu điểm của việc tạo các trình phân tích với một DocumentBuilder là sự kiểm soát các thiết lập trên các trình phân tích được tạo bởi DocumentBuilderFactory. Ví dụ, trình phân tích có thể được thiết lập để phê chuẩn tài liệu:

...

try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
          dbf.setValidating(true); 
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(docFile);
      } catch (Exception e) {
...

Thực thi DOM Mức 2 của Java cho phép kiểm soát các tham số cho một trình phân tích thông qua các phương thức dưới đây:

  • setCoalescing(): Quyết định liệu trình phân tích chuyển các nút CDATA thành văn bản hay không, và kết hợp chúng với các nút văn bản xung quanh (nếu có thể áp dụng). Giá trị mặc định là false.
  • setExpandEntityReferences(): Quyết định liệu các tham chiếu thực thể bên ngoài được mở rộng hay không. Nếu là true, dữ liệu bên ngoài được chèn vào trong tài liệu. Giá trị mặc định là true. (Xem Tài nguyên để tìm hiểu thêm về làm việc với các thực thể bên ngoài.)
  • setIgnoringComments(): Quyết định các chú thích trong tệp có bị từ chối hay không. Giá trị mặc định là false.
  • setIgnoringElementContentWhitespace(): Quyết định liệu ký tự trắng trong các nội dung phần tử có bị từ chối hay không (giống như cách một trình duyệt đối xử với HTML). Giá trị mặc định là false.
  • setNamespaceAware(): Quyết định liệu trình phân tích có cần quan tâm đến thông tin không gian tên hay không. Giá trị mặc định là false.
  • setValidating(): Mặc định, các trình phân tích sẽ không phê chuẩn các tài liệu. Thiết lập sang true để bật chức năng phê chuẩn.

Các ngoại lệ trình phân tích

Với tất cả các khả năng khác nhau trong việc tạo ra một trình phân tích, thì rất nhiều lỗi có thể xảy ra. Ví dụ, ứng dụng xổ tất cả chúng thành một Exception chung và đơn lẻ, điều này có thể không hữu ích đối với quá trình gỡ lỗi.

Để xác định các vấn đề tốt hơn, bạn có thể bắt những ngoại lệ cụ thể liên quan tới nhiều khía cạnh của việc tạo ra và sử dụng một trình phân tích:

...

      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(docFile);
 } catch (javax.xml.parsers.ParserConfigurationException pce) { System.out.println(
"The parser was not configured correctly."); System.exit(1); } catch 
(java.io.IOException ie) { System.out.println("Cannot read input file."); 
System.exit(1); } catch (org.xml.sax.SAXException se) { System.out.println(
"Problem parsing the file."); System.exit(1); } catch 
(java.lang.IllegalArgumentException ae) { System.out.println(
"Please specify an XML source."); 
System.exit(1); 
      }
...

Khi trình phân tích đã tạo ra một Document, ứng dụng có thể bước qua nó để kiểm tra dữ liệu.


Bước qua tài liệu

Lấy phần tử gốc

Khi tài liệu được phân tích và một Document được tạo ra, thì một ứng dụng có thể bước qua cấu trúc để xem lại, tìm, hay hiển thị thông tin. Điều hướng này là cơ sở cho nhiều thao tác sẽ được thực hiện trên một Document.

Bắt đầu việc bước qua tài liệu với phần tử gốc. Một tài liệu được tổ chức tốt chỉ có một phần tử gốc, cũng được biết đến như là DocumentElement. Đầu tiên, ứng dụng truy lục phần tử này.

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import org.w3c.dom.Document;
 import org.w3c.dom.Element;

public class OrderProcessor {
...
      System.exit(1);
   }

   //Bước 1:  Lấy phần tử gốc
 Element root = doc.getDocumentElement(); System.out.println("The root element is 
" + root.getNodeName()); 
 }
}

Biên dịch và chạy ứng dụng sẽ xuất ra tên của phần tử gốc, orders.

Lấy các nút con của một nút

Khi ứng dụng quyết định phần tử gốc, nó truy lục một danh sách các nút con của phần tử gốc như là một NodeList. Lớp NodeList là một loạt các mục mà qua chúng ứng dụng có thể lặp lại. Trong ví dụ này, để đơn giản, ứng dụng lấy các nút con và xác minh sự phục hồi bằng cách chỉ hiển thị số lượng phần tử xuất hiện trong kết quả NodeList.

Chú ý rằng tài liệu này chỉ có hai phần tử, nhưng NodeList chứa năm nút con, bao gồm ba nút văn bản chứa các tín hiệu chuyển dòng -- một chú ý nữa là các nút và các phần tử không tương thích trong DOM. Ba nút khác là các nút văn bản.

...

 import org.w3c.dom.NodeList; 
...
   //Bước 1:  Lấy phần tử gốc
   Element root = doc.getDocumentElement();
   System.out.println("The root element is "+root.getNodeName());
      
   //Bước 2:  Lấy nút con
 NodeList children = root.getChildNodes(); System.out.println("There are "
+children.getLength() +" nodes in this document.");
                                  
 }
}

Sử dụng getFirstChild() và getNextSibling()

Các mối quan hệ cha-con và anh-em cung cấp một phương tiện thay thế để lặp lại qua tất cả các nút con của một nút, điều này có thể thích hợp trong một số hoàn cảnh, như là khi các mối quan hệ này và trật tự mà ở đó các nút con xuất hiện. Điều này rất quan trọng trong việc hiểu dữ liệu.

Trong Bước 3, một for-loop bắt với nút đầu tiên của phần tử gốc. Ứng dụng lặp lại qua mỗi nút anh-em của nút con đầu tiên cho đến khi tất cả chúng được đánh giá.

Mỗi lần ứng dụng thi hành vòng lặp, nó truy lục một đối tượng Node, xuất ra tên và giá trị của nó. Chú ý rằng năm nút con của orders bao gồm các phần tử order và ba nút văn bản. Cũng cần chú ý rằng các phần tử mang một giá trị null, hơn là văn bản được mong muốn. Các nút văn bản là nút con của các phần tử mang nội dung hiện thời như các giá trị của chúng.

...

 import org.w3c.dom.Node; 

...
      
      //Bước 3: Bước qua các nút con
 for (Node child = root.getFirstChild(); child != null; child = child.getNextSibling()) 
{ System.out.println(start.getNodeName()+" = " +start.getNodeValue()); } 
   }
}
...

Đệ quy qua nhiều mức của các nút con

Mã trình trong Sử dụng getFirstChild() và getNextSibling() biểu thị các nút con ở mức đầu tiên, nhưng đó không phải toàn bộ tài liệu. Để xem tất cả các phần tử, tính năng trong ví dụ trước phải được chuyển thành một phương pháp và được gọi theo đệ quy.

Ứng dụng bắt đầu với phần tử gốc và in tên và giá trị ra màn hình. Sau đó, ứng dụng chạy qua các nút con của nó như trước đó. Nhưng đối với mỗi nút con, ứng dụng cũng chạy qua mỗi nút con của chúng để kiểm tra tất cả các nút con và nút cháu của phần tử nguồn.

...

public class OrderProcessor {
   
 private static void stepThrough (Node start) { 
      System.out.println(start.getNodeName()+" = "+start.getNodeValue());   

      for (Node child = start.getFirstChild(); 
          child != null;
          child = child.getNextSibling())
      {
 stepThrough(child); 
      }
 } 

   public static void main (String args[]) {
      File docFile = new File("orders.xml");
      
...     
      System.out.println("There are "+children.getLength()
                            +" nodes in this document.");

      //Bước 4:  Đệ quy tính năng này
 stepThrough(root); 
   }
}

Bao gồm các thuộc tính

Các phương pháp stepThrough() như được viết ở trên có thể chạy qua phần lớn các loại nút, nhưng nó thiếu toàn bộ các thuộc tính bởi vì chúng không phải là nút con của bất cứ nút nào. Để hiển thị các thuộc tính, hãy sửa đổi stepThrough() để kiểm tra các nút phần tử cho các thuộc tính.

Mã trình được sửa đổi dưới đây kiểm tra mỗi đầu ra nút để xem liệu nó là một phần tử hay không bằng cách so sánh nodeType của nó với giá trị hằng số ELEMENT_NODE. Một đối tượng Node mang các hằng số thành viên là các loại của nút, như là ELEMENT_NODE hay ATTRIBUTE_NODE. Nếu nodeType khớp với ELEMENT_NODE, nó là một phần tử.

Đối với các phần tử được tìm thấy, ứng dụng tạo ra một NamedNodeMap chứa tất cả thuộc tính dành cho phần tử. Ứng dụng có thể lặp qua một NamedNodeMap, in ra tên và giá trị của mỗi thuộc tính, giống như nó đã lặp qua NodeList.

...

 import org.w3c.dom.NamedNodeMap; 
...
private static void stepThroughAll (Node start)
   {
      System.out.println(start.getNodeName()+" = "+start.getNodeValue());   
         
 if (start.getNodeType() == start.ELEMENT_NODE) { 
NamedNodeMap startAttr = start.getAttributes(); 
for (int i = 0; i < startAttr.getLength(); i++) { Node attr = startAttr.item(i); 
System.out.println(" Attribute: "+ attr.getNodeName() +" = 
"+attr.getNodeValue()); } } 
      
      for (Node child = start.getFirstChild(); 
          child != null;
          child = child.getNextSibling())
      {
         stepThroughAll(child);
      }
   }

Biên tập tài liệu

Thay đổi giá trị của một nút

Rất hữu ích khi xem lại các nội dung của một tài liệu XML, nhưng khi làm việc với các ứng dụng có tính năng đầy đủ bạn có thể phải cần thay đổi dữ liệu để thêm, sửa, di chuyển, hay xóa thông tin. Khả năng sửa dữ liệu cũng rất quan trọng đối với quá trình tạo ra các tài liệu XML mới. Đơn giản nhất là thay đổi làm ảnh hưởng đến nội dung văn bản của một phần tử.

Mục đích ở đây là để thay đổi giá trị của nút văn bản của một phần tử, trong trường hợp này, bằng việc thiết lập status của mỗi order để "được xử lý", và sau đó in những giá trị mới ra màn hình.

Phương pháp changeOrder() được gọi với nút khởi đầu (root ) như một tham số, cũng như cả tên của phần tử thay đổi và giá trị nó được thay đổi sang.

changeOrder() đầu tiên kiểm tra tên của nút để xem liệu nó là một trong những phần tử để sửa hay không. Nếu đúng, ứng dụng cần thay đổi giá trị của không chỉ nút này mà còn của nút con đầu tiên của nó, vì nút con đầu tiên này thực chất là nút văn bản chứa nội dung.

Trong mỗi trường hợp, ứng dụng kiểm tra mỗi nút con, giống như nó thực hiện trong việc bước qua tài liệu lần đầu tiên.

Khi các thay đổi hoàn thành, các giá trị được kiểm tra bằng cách sử dụng getElementsByTagName(). Phương pháp này trả về một danh sách của tất cả các phần tử con với một tên cụ thể, như là status. Sau đó, ứng dụng có thể kiểm danh sách để lấy các giá trị để xác minh rằng changeOrder() đã làm việc.

...

public class OrderProcessor {
 private static void changeOrder 
(Node start, String elemName, String elemValue) 
{ if (start.getNodeName().equals(elemName)) 
{ start.getFirstChild().setNodeValue(elemValue); } 
for (Node child = start.getFirstChild(); 
child != null; child = child.getNextSibling()) 
{ changeOrder(child, elemName, elemValue); } } 
...
   public static void main (String args[]) {
...
      
     // Thay đổi nội dung văn bản
 changeOrder(root, "status", "processing"); NodeList orders = 
root.getElementsByTagName("status"); 
for (int orderNum = 0; orderNum < orders.getLength(); orderNum++) 
{ System.out.println(orders.item(orderNum) .getFirstChild().getNodeValue()); }  }
}

Chú ý rằng ứng dụng vẫn tìm được các nút status mặc dù chúng là các nút cháu của phần tử gốc, và không phải nút con trực tiếp. getElementsByTagName() bước qua tài liệu và tìm thấy tất cả các phần tử với một tên nhất định.

Thêm các nút: chuẩn bị dữ liệu

Thay vì thay đổi một nút đã tồn tại, thỉnh thoảng cũng cần phải thêm một nút mới, và bạn có thể làm theo một số cách. Trong ví dụ này, ứng dụng tính tổng chi phí cho mỗi order và thêm một phần tử total. Nó tính tổng bằng cách lấy mỗi đơn đặt hàng và lặp qua mỗi mục của nó để lấy chi phí mục, và sau đó tính tổng của chúng. Sau đó, ứng dụng thêm mới phần tử vào trong đơn đặt hàng (xem ví dụ mã trình dưới đây).

Đầu tiên, ứng dụng truy lục các phần tử order như nó đã từng truy lục các phần tử status. Sau đó, nó lặp qua mỗi các phần tử này.

Đối với mỗi order này, ứng dụng cần một NodeList của các phần tử item của nó, nên ứng dụng đầu tiên phải quảng bá order Node với Element để sử dụng getElementsByTagName().

Ứng dụng có thể lặp qua các phần tử item dành cho order được lựa chọn. Lần lượt, nó quảng bá tới Element để nó có thể truy lục priceqty bằng tên. Nó thực hiện điều đó bằng cách sử dụng getElementsByTagName(), và bởi vì chỉ có một trong số đó là có thể đi trực tiếp tới item(0), mục vào đầu tiên trong kết quả NodeList. Mục vào đầu tiên cho biết phần tử price (hay qty ). Từ đó, giá trị của nút văn bản được lấy ra.

Giá trị của nút văn bản là một giá trị String, mà ứng dụng sau đó chuyển đổi thành một double cho phép các phép toán cần thiết.

Khi ứng dụng kiểm tra xong tất cả các mục dành cho mỗi đơn đặt hàng, total là một double cho biết giá trị tổng. Sau đó, total được chuyển đổi thành một String nên nó có thể được sử dụng như nội dung của một phần tử mới, <total>, phần tử mới này cuối cùng sẽ nhập vào order.

...

changeOrder(root, "status", "processing");
NodeList orders = root.getElementsByTagName(" order ");
for (int orderNum = 0; 
     orderNum < orders.getLength(); 
     orderNum++) 
{
 Element thisOrder = (Element)orders.item(orderNum); NodeList orderItems = 
thisOrder.getElementsByTagName("item"); double total = 0; for (int itemNum = 0; 
itemNum < orderItems.getLength(); 
itemNum++) { // Tính tổng chi phí cho mỗi mục và // 
thêm vào tổng đơn đặt hàng //Lấy mục này như một Phần tử Element thisOrderItem = 
(Element)orderItems.item(itemNum); //Lấy thông tin giá cho Mục này 
String thisPrice = 
thisOrderItem.getElementsByTagName("price").item(0) .getFirstChild().getNodeValue(); 
double thisPriceDbl = new Double(thisPrice).doubleValue(); 
//Lấy thông tin số lượng cho Mục này String thisQty = 
thisOrderItem.getElementsByTagName("qty").item(0) .getFirstChild().getNodeValue(); 
double thisQtyDbl = new Double(thisQty).doubleValue(); double thisItemTotal = 
thisPriceDbl*thisQtyDbl; total = total + thisItemTotal; } String totalString = 
new Double(total).toString(); 
}
...

Thêm các nút: thêm các nút vào tài liệu

Bạn có thể tạo ra một Node mới bằng nhiều cách khác nhau, và ví dụ này sẽ sử dụng một trong số cách như vậy. Đầu tiên, đối tượng Document có thể tạo ra một nút văn bản mới, với totalString như giá trị. Bây giờ Node nút mới đã tồn tại, nhưng nó chưa được gắn vào Document. Phần tử total cũng được tạo ra theo cách tương tự, và nó cũng tách ra để khởi đầu với.

Một cách khác để thêm một nút là sử dụng appendChild(), như được thấy ở đây, để thêm nút vào phần tử total mới.

Cuối cùng, ứng dụng có thể sử dụng insertBefore() để thêm mới một phần tử vào Document, để chỉ định Node mới, và sau đó là Node nó đứng trước.

Bước qua tài liệu để xác minh những thay đổi.

...

changeOrder(root, "status", "processing");
NodeList orders = root.getElementsByTagName("order");
for (int orderNum = 0; 
     orderNum < orders.getLength(); 
     orderNum++) 
{
...
    String totalString = new Double(total).toString();
 Node totalNode = doc.createTextNode(totalString); Element totalElement = 
doc.createElement("total"); totalElement.appendChild(totalNode); 
thisOrder.insertBefore(totalElement, thisOrder.getFirstChild()); 
}
 stepThrough(root); 
...

Xóa một nút

Thay vì phải thay thế văn bản của một phần tử, ứng dụng có thể xóa nó vĩnh viễn. Trong ví dụ này, ứng dụng sẽ kiểm tra để xem liệu mục có trong kho hay không. Nếu không, nó sẽ xóa mục từ đơn đặt hàng thay vì thêm nó vào tổng số.

Trước khi thêm chi phí của một mục vào tổng số, ứng dụng kiểm tra giá trị của thuộc tính instock. Nếu nó là N, thì thay vì được thêm vào tổng số, mục được xóa hoàn toàn. Để làm điều đó, nó sử dụng phương pháp removeChild(), nhưng đầu tiên phải quyết định nút cha của orderItem bằng cách sử dụng getParentNode(). Node đã được xóa khỏi tài liệu, nhưng phương pháp này cũng trả nó về như một đối tượng, nên nó có thể được xóa nếu muốn.

...

   //Lấy mục này như một Phần tử
   Element thisOrderItem = (Element)orderItems.item(itemNum);

 if (thisOrderItem.getAttributeNode("instock") .getNodeValue().equals("N")) 
{ Node deadNode = thisOrderItem.getParentNode().removeChild(thisOrderItem); } else { 
      //Lấy thông tin giá cho Mục này
      String thisPrice = 
                   thisOrderItem.getElementsByTagName("price").item(0)
                                      .getFirstChild().getNodeValue();
...
      total = total + thisItemTotal;
 } 
}
String totalString = new Double(total).toString();

...

Thay thế một nút

Tất nhiên, nó không có nghĩa là xóa một mục bởi vì nó được đặt hàng sau. Thay vào đó, ứng dụng sẽ thay thế nó bằng một mục backordered.

Thay vì sử dụng removeChild(), đơn giản hãy sử dụng replaceChild(). Chú ý rằng trong trường hợp này, phương pháp cũng trả về một nút trước đây, nên nó có thể được di chuyển, nếu thấy cần thiết, tới một Document mới liệt kê ra các mục đặt hàng tồn.

Chú ý rằng bởi vì nội dung không được thêm vào phần tử, nó là một phần tử trống. Một phần tử trống không có nội dung, và có thể được viết bằng một tốc ký đặc biệt:

<backordered />

Dấu gạch chéo (/ ) loại trừ sự cần thiết dành cho một thẻ kết thúc ( </backordered> ).

...

   if (thisOrderItem.getAttributeNode("instock")
                  .getNodeValue().equals("N")) {
					
 Element backElement = doc.createElement("backordered"); 
      Node deadNode = thisOrderItem.getParentNode()
                . replaceChild ( backElement,  thisOrderItem);


   } else {
...

Tạo và thiết lập các thuộc tính

Tất nhiên, một phần tử backordered sẽ thực hiện thế nào nếu không có chỉ dẫn của mục nó? Một cách để hiệu chỉnh sự thiếu thông tin là thêm một thuộc tính vào phần tử.

Đầu tiên, ứng dụng tạo ra một thuộc tính itemid. Tiếp theo, nó quyết định giá trị của itemid từ phần tử item gốc, và sau đó nó tự thiết lập giá trị của thuộc tính. Cuối cùng, nó thêm phần tử vào tài liệu, giống như trước đây.

...

if (thisOrderItem.getAttributeNode("instock")
                  .getNodeValue().equals("N")) {
					
   Element backElement = doc.createElement("backordered");

 backElement.setAttributeNode(doc.createAttribute("itemid")); 
String itemIdString = 
thisOrderItem.getAttributeNode("itemid").getNodeValue(); 
backElement.setAttribute("itemid", itemIdString); 

   Node deadNode = thisOrderItem.getParentNode().replaceChild(backElement,
                                                        thisOrderItem);

} else {
...

Đặc biệt chú ý rằng setAttribute() tạo ra nút thuộc tính nếu nút có tên đó không tồn tại, nên trong trường hợp này, ứng dụng có thể bỏ qua toàn bộ createAttribute().

Xóa một thuộc tính

Một ứng dụng cũng có thể xóa các thuộc tính. Ví dụ, nó có thể không thích để thông tin hạn chế tin cậy khách hàng biểu thị trong đầu ra, nên ứng dụng có thể tạm thời xóa nó khỏi tài liệu.

Xóa thông tin tương đối dễ dàng, sử dụng removeAttribute() để xóa dữ liệu.

...

Element thisOrder = (Element)orders.item(orderNum);
 Element customer = (Element)thisOrder.getElementsByTagName("customerid") .item(0); 
customer.removeAttribute("limit"); 
NodeList orderItems = thisOrder.getElementsByTagName("item");
...

Mặc dù vậy, bước tiếp theo sử dụng thông tin giới hạn, bạn nên xóa thay đổi cuối cùng trước khi tiếp tục bước tiếp theo.


Xuất ra tài liệu

Chuẩn bị dữ liệu

Hướng dẫn này đã đề cập tới việc lấy, làm việc với, và chế tác dữ liệu XML. Để hoàn thành chu trình, bạn cũng phải biết cách xuất ra XML.

Trong trường hợp này, đầu ra mục tiêu là một tệp liệt kê ra mỗi đơn đặt hàng, cho dù nó được xử lý hay bị từ chối dựa trên sự hạn chế tín dụng của khách hàng, và customerid.

 <?xml version="1.0" encoding="UTF-8"?>
<processedOrders>
   <order>
	  <status>PROCESSED</status>
	  <customerid>2341</customerid>
	  <amount>874.00</amount>
   </order>
   <order>
	  <status>REJECTED</status>
	  <customerid>251222</customerid>
	  <amount>200.00</amount>
   </order>
</processedOrders>

Đầu tiên, ứng dụng tạo ra đối tượng Document để xuất ra. Để thuận tiện, DocumentBuilder mà đã tạo ra Document gốc sẽ được sử dụng để tạo ra tài liệu mới.

...

   public static void main (String args[]) {
      File docFile = new File("orders.xml");
      Document doc = null;  
       Document newdoc = null; 
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(docFile);
		 
 newdoc = db.newDocument(); 
		 
      } catch (Exception e) {
         System.out.print("Problem parsing the file: "+e.getMessage());
      }
...
   thisOrder.insertBefore(totalElement, thisOrder.getFirstChild());
}

 Element newRoot = newdoc.createElement("processedOrders"); 
NodeList processOrders = 
doc.getElementsByTagName("order"); for (int orderNum = 0; orderNum 
< processOrders.getLength(); 
orderNum++) { Element thisOrder = (Element)processOrders.item(orderNum); 
Element customerid = 
(Element)thisOrder.getElementsByTagName("customerid") .item(0); 
String limit = 
customerid.getAttributeNode("limit").getNodeValue(); String total = 
thisOrder.getElementsByTagName("total").item(0) .getFirstChild().getNodeValue(); 
double limitDbl = new Double(limit).doubleValue(); double totalDbl = 
new Double(total).doubleValue(); Element newOrder = newdoc.createElement("order"); 
Element newStatus = newdoc.createElement("status"); if (totalDbl > limitDbl) 
{ newStatus.appendChild(newdoc.createTextNode("REJECTED")); } else 
{ newStatus.appendChild(newdoc.createTextNode("PROCESSED")); } 
Element newCustomer = newdoc.createElement("customerid"); 
String oldCustomer = customerid.getFirstChild().getNodeValue(); 
newCustomer.appendChild(newdoc.createTextNode(oldCustomer)); Element newTotal = 
newdoc.createElement("total"); newTotal.appendChild(newdoc.createTextNode(total)); 
newOrder.appendChild(newStatus); newOrder.appendChild(newCustomer); 
newOrder.appendChild(newTotal); newRoot.appendChild(newOrder); } 
newdoc.appendChild(newRoot); 
System.out.print(newRoot.toString()); 
...

Sau khi xử lý orders.xml, ứng dụng sẽ tạo mới một phần tử, processedOrders, và cuối cùng phần tử này sẽ trở thành phần tử gốc của một tài liệu mới. Sau đó, nó chạy qua các đơn đặt hàng. Với mỗi đơn đặt hàng, nó sẽ trích ra thông tin về totallimit.

Tiếp theo, ứng dụng tạo ra các phần tử mới cho đơn đặt hàng: order, status, customerid, và amount. Nó sinh ra status dựa trên liệu tổng số có vượt qua giới hạn tín dụng của khách hàng hay không, và sẽ sinh ra các trạng thái tương ứng.

Khi ứng dụng tạo ra các phần tử, nó phải tập hợp chúng với nhau. Đầu tiên, nó thêm trạng thái, khách hàng, thông tin, và tổng số vào trong phần tử order mới. Sau đó, nó thêm mới order vào phần tử newRoot.

Trong khi quá trình này diễn ra, phần tử newRoot chưa được gắn với một nút cha. Khi ứng dụng xử lý xong tất cả các đơn đặt hàng, newRoot được kết nối với tài liệu mới.

Cuối cùng, ứng dụng xuất ra dữ liệu bằng cách chuyển đổi newRoot thành một String và gửi nó tới System.out.

Chú ý: Một số phiên bản của mã trình Java không hỗ trợ phiên bản này của toString() trên một nút. Trong trường hợp đó, hãy sử dụng kỹ thuật được miêu tả trong Các chuyển đổi nhận dạng để xem nội dung của nút.

Tạo một Tệp XML

Bây giờ, ứng dụng đã tạo ra thông tin mới, việc xuất nó ra một tệp tương đối dễ dàng.

Logic giống như vậy cũng được sử dụng cho dữ liệu, nhưng thay vì xuất nó ra màn hình, ứng dụng gửi nó tới một tệp.

Điều quan trọng cần chú ý ở đây là vì dữ liệu XML chỉ là văn bản, nó có thể được định dạng bằng nhiều cách khác nhau. Ví dụ, bạn có thể tạo ra một biến dạng trên stepThroughAll() điều này sẽ tạo ra một phiên bản lõm, hay được in tốt. Nhưng hãy ghi nhớ rằng nó sẽ tạo ra thêm những nút (văn bản) ký tự trắng.

...

 import java.io.FileWriter; 
...

 try { File newFile = new File("processedOrders.xml"); FileWriter newFileStream = 
new FileWriter(newFile); newFileStream.write ("<?xml version=\"1.0\"?>");

    newFileStream.write ("<!DOCTYPE
"+doc.getDoctype().getName()+" ");

   if (doc.getDoctype().getSystemId() != null) {

       newFileStream.write (" SYSTEM ");

       newFileStream.write (doc.getDoctype().getSystemId());
   }
   if (doc.getDoctype().getPublicId() != null) {

       newFileStream.write (" PUBLIC ");

       newFileStream.write (doc.getDoctype().getPublicId());
   }

    newFileStream.write (">");

    newFileStream.write (newRoot.toString());

    newFileStream.close(); } catch (IOException e) 
{ System.out.println("Can't write new file."); }
...

Các chuyển đổi nhận dạng

Với những Document đơn giản như trong hướng dẫn này, bạn có thể dễ dàng kết luận rằng xuất ra XML rất đơn giản, nhưng hãy nhớ xem xét nhiều yếu tố làm phức tạp vấn đề -- các sự cố đặc biệt, như nội dung của các tệp bị ảnh hưởng bởi một DTD hay lược đồ. Trong phần lớn các trường hợp, bạn nên dựa theo ứng dụng đã đã đề cập tất cả những khả năng này vào trong tài khoản.

Một cách thông dụng mà những người phát triển thường chọn để xuất bản các DOM Document là tạo ra một chuyển đổi nhận dạng. Đây là một Chuyển đổi XSL không bao gồm một trang định dạng. Ví dụ:

...

 import javax.xml.transform.TransformerFactory; import javax.xml.transform.Transformer; 
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; 
import java.io.FileOutputStream;
...
     newdoc.appendChild(newRoot);

 try { DOMSource source = new DOMSource(newdoc); StreamResult result = 
new StreamResult(new FileOutputStream("processed.xml")); 
TransformerFactory transFactory = 
TransformerFactory.newInstance(); Transformer transformer = 
transFactory.newTransformer(); 
transformer.transform(source, result); } catch (Exception e){ e.printStackTrace(); }
  }
}

Ở đây, bạn đang tạo ra một nguồn và một kết quả, nhưng bởi vì bạn đang làm việc với một chuyển đổi nhận dạng, bạn không tạo ra một đối tượng để miêu tả trang định dạng. Nếu đây là một chuyển đổi hiện thời, trang định dạng sẽ được sử dụng trong việc tạo ra Transformer. Thay vào đó, Transformer đơn giản lấy nguồn (Document) và gửi nó tới tệp kết quả (processed.xml).


Tóm tắt Mô hình Đối tượng Tài liệu

Tóm tắt

DOM là một API độc lập về ngôn ngữ và nền được thiết kế để làm việc với dữ liệu XML. Nó là một API dựa trên biểu đồ hình cây nạp tất cả dữ liệu vào trong bộ nhớ như một hệ đẳng cấp cha-con của các nút, nó có thể là các phần tử, văn bản, thuộc tính, hay các kiểu nút khác.

DOM API cho phép một người phát triển đọc, tạo ra, và sửa dữ liệu XML. Hướng dẫn này đã đưa ra các khái niệm phía sau DOM và minh họa chúng bằng các ví dụ trong mã trình Java. Những thực thi của DOM cũng được sử dụng trong C++, Perl, và các ngôn ngữ khác.

Tài nguyên

Học tập

  • Bạn có thể tìm hiểu kiến thức cơ bản về XML trong hướng dẫn "Giới thiệu về XML" (developerWorks, tháng Tám năm 2002).
  • Truy cập vào trang W3C DOM để tìm hiểu về các Đề nghị DOM cho Mức 1, Mức 2, và Mức 3.
  • Bài viết "Di chuyển các nút DOM" của tác giả Brett McLaughlin nghiên cứu về cách di chuyển các nút từ một tài liệu này sang một tài liệu khác mà không bị một ngoại lệ phổ biến (developerWorks, tháng Ba năm 2001).
  • Hãy đọc bài viết của Brett McLaughlin có tựa đề "Chuyển đổi từ DOM" để tìm hiểu cách chuyển một DOM Document thành một luồng SAX hay tài liệu JDOM (developerWorks, tháng Tư năm 2001).
  • Đọc bài viết "Kiểm tra một tài liệu với một TreeWalker" (developerWorks, tháng Mười năm 2002) của tác giả Nicholas Chase để biết cách luân phiên kiểm tra một tài liệu sử dụng mô đun Traversal của DOM Mức 2, và bài viết "Sử dụng một DOM NodeFilter" của ông để biết cách mở rộng trên khả năng đó (developerWorks, tháng Mười Một năm 2002).
  • Một phiên bản đối với DOM là API Đơn giản dành cho XML (viết tắt là SAX). SAX cho phép bạn xử lý một tài liệu ngay khi nó đang được đọc, điều này tránh được việc phải chờ cho tất cả tài liệu được lưu trữ trước khi xử lý. Tìm hiểu thêm về SAX trong hướng dẫn trên developerWorks có tựa đề "Hiểu về SAX" (được cập nhật tháng Bảy năm 2003).
  • Hãy đặt mua XML Primer Plus của Nicholas Chase, tác giả của hướng dẫn này, tại (http://www.amazon.com/exec/obidos/ASIN/0672324229/ref=nosim/thevanguardsc-20).
  • Tìm hiểu cách bạn có thể trở thành một IBM-Certified Developer về XML và các công nghệ liên quan (http://www-1.ibm.com/certify/certs/adcdxmlrt.shtml).

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

  • Tải về Java 2 SDK, Standard Edition phiên bản 1.4.2 tại (http://java.sun.com/j2se/1.4.2/download.html).
  • Nếu bạn đang sử dụng phiên bản cũ của Java, hãy tải về Xerces-Java của dự án Apache tại (http://xml.apache.org/xerces2-j/index.html), hay Java API dành cho Phân tích XML của Sun (JAXP), là một phần của gói Java Web Services Developer Pack (http://java.sun.com/webservices/downloads/webservicespack.html).
  • Tải về Xerces C++, một trình phân tích phê chuẩn DOM tại (http://xml.apache.org/xerces-c/index.html).
  • Tải về Xerces.pm, một Perl API được thực thi bằng cách sử dụng Xerces C++ API cung cấp truy cập cho gần như tất cả C++ API từ Perl (http://xml.apache.org/xerces-p/index.html).
  • Lấy cơ sở dữ liệu DB2 của IBM (http://www.ibm.com/software/data/db2/). Cơ sở dữ liệu này cung cấp không chỉ lưu trữ cơ sở dữ liệu quan hệ, mà còn các công cụ liên quan đến XML như là DB2 XML Extender (http://www.ibm.com/software/data/db2/extenders/xmlext/) nó cung cấp một cầu nối giữa XML và các hệ thống quan hệ. Hãy truy cập khu vực nội dung DB2 để biết thêm thông tin về DB2 (http://www.ibm.com/developerworks/db2).

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ở
ArticleID=413482
ArticleTitle=Tìm hiểu về DOM
publish-date=03122007