1. Làm quen với XML
Mặc dù ngày nay JSON là tiêu chuẩn, trong thế giới Java vẫn còn rất nhiều mã legacy, nên đôi khi bạn sẽ gặp XML. Vì thế, có hiểu biết về nó là điều hữu ích. XML (eXtensible Markup Language) là định dạng văn bản để lưu trữ và trao đổi dữ liệu có cấu trúc. Nó thường được dùng cho cấu hình, trao đổi giữa các chương trình, lưu trữ dữ liệu và thậm chí để tuần tự hóa (serialization) đối tượng.
Các thành phần chính của cấu trúc tài liệu XML:
Thẻ (phần tử):
Mọi thứ nằm giữa < và >. Mỗi thẻ có thẻ mở (<tag>) và thẻ đóng (</tag>), hoặc là thẻ tự đóng (<tag/>).
Thuộc tính:
Các tham số bổ sung bên trong thẻ.
Ví dụ: <user name="Vasya" age="25"/>
Nút văn bản:
Văn bản nằm giữa các thẻ.
Ví dụ: <greeting>Xin chào, thế giới!</greeting>
Ví dụ về tài liệu XML đơn giản
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user name="Vasya" age="25">Xin chào!</user>
<user name="Katya" age="30"/>
</users>
Ở đây:
- <users> — phần tử gốc.
- <user> — phần tử có thuộc tính name và age; người dùng đầu tiên có nội dung văn bản.
2. Khái niệm cốt lõi
Prolog:
Dòng ở đầu tệp cho biết phiên bản XML và mã hóa ký tự.
Ví dụ: <?xml version="1.0" encoding="UTF-8"?>
Phần tử:
Khối xây dựng cơ bản của XML.
Ví dụ: <book>...</book>
Thuộc tính:
Các tham số nằm trong thẻ mở.
Ví dụ: <book title="Java" author="Ivanov"/>
Chú thích:
Giống như trong HTML, được viết giữa <!-- ... -->.
Ví dụ: <!-- Đây là chú thích -->
Phần CDATA:
Cho phép chèn văn bản sẽ không bị diễn giải như XML (ví dụ, có các ký tự <, & v.v.).
Ví dụ:
<script><![CDATA[
if (a < b && b > 0) { ... }
]]></script>
3. Tại sao cần namespaces (không gian tên) trong XML
Vấn đề: xung đột tên
Trong các tài liệu XML lớn, thường có những tên thẻ giống nhau nhưng ý nghĩa khác nhau. Ví dụ, bạn có <table> như một phần của HTML và <table> là một phần của logic nghiệp vụ của bạn (ví dụ, cơ sở dữ liệu). Làm sao biết thẻ nào mang ý nghĩa gì?
Không có namespace:
<root>
<table>
<row>...</row>
</table>
<table>
<column>...</column>
</table>
</root>
Ở đây không rõ thẻ <table> thuộc về phần nào.
Giải pháp: namespaces
Namespace (không gian tên) là cách “đánh dấu” các phần tử và thuộc tính để tránh xung đột tên và phân tách rõ ràng ý nghĩa của các thẻ khác nhau.
- Mỗi namespace là một URI duy nhất (thường trông như một liên kết, nhưng chỉ là một định danh).
- Các phần tử và thuộc tính có namespace khác nhau được xem là khác nhau, ngay cả khi tên trùng nhau.
Ưu điểm:
- Không có xung đột tên giữa các tiêu chuẩn và schema khác nhau.
- Có thể hợp nhất dữ liệu từ nhiều nguồn trong cùng một tài liệu.
- Thấy rõ mỗi thẻ thuộc về “từ điển” nào.
4. Cách sử dụng namespaces: khai báo và áp dụng
Cách khai báo namespace
Trong thẻ mở của phần tử, dùng thuộc tính đặc biệt xmlns (XML Namespace):
- Không có tiền tố: xmlns="URI" — khai báo namespace mặc định cho tất cả phần tử lồng bên trong.
- Có tiền tố: xmlns:prefix="URI" — khai báo namespace với tên ngắn (tiền tố), dùng cho các thẻ.
Ví dụ khai báo và sử dụng namespace
<root xmlns:h="http://www.w3.org/TR/html4/"
xmlns:f="http://www.w3schools.com/furniture">
<h:table>
<h:tr>
<h:td>Ô 1</h:td>
<h:td>Ô 2</h:td>
</h:tr>
</h:table>
<f:table>
<f:name>Bàn</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
</root>
Ở đây:
- xmlns:h="..." — khai báo tiền tố h cho bảng HTML.
- xmlns:f="..." — khai báo tiền tố f cho đồ nội thất.
- <h:table> và <f:table> — giờ là các phần tử khác nhau, dù tên giống nhau.
Cách áp dụng namespace
- Khai báo: Ở phần tử gốc hoặc bất kỳ phần tử nào: xmlns:prefix="URI"
- Áp dụng: Đặt tiền tố và dấu hai chấm trước tên phần tử hoặc thuộc tính: <prefix:element>...</prefix:element>
Namespace mặc định
Nếu chỉ khai báo xmlns="URI", tất cả phần tử không có tiền tố sẽ thuộc namespace đó.
<books xmlns="http://example.com/books">
<book>...</book>
</books>
5. Thực hành: tạo tài liệu XML đơn giản với nhiều namespace
Hãy tạo ví dụ tài liệu XML có hai không gian tên: cho HTML và cho đồ nội thất.
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:h="http://www.w3.org/TR/html4/"
xmlns:f="http://www.w3schools.com/furniture">
<h:table>
<h:tr>
<h:td>Ô 1</h:td>
<h:td>Ô 2</h:td>
</h:tr>
</h:table>
<f:table>
<f:name>Bàn</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
</root>
Điều gì đang diễn ra ở đây:
- Trong phần tử gốc, có hai namespace được khai báo: h và f.
- Tất cả các phần tử có tiền tố h: thuộc về bảng HTML.
- Tất cả các phần tử có tiền tố f: thuộc về đồ nội thất.
6. Các lỗi thường gặp
Lỗi 1: quên khai báo tiền tố
<root>
<h:table>...</h:table>
</root>
Kết quả: Trình phân tích XML sẽ báo lỗi: The prefix 'h' for element 'h:table' is not bound.
Lỗi 2: tên giống nhau nhưng không có namespace
<root>
<table>...</table>
<table>...</table>
</root>
Kết quả: Không thể phân biệt thẻ <table> thuộc về phần nào.
Lỗi 3: sử dụng tiền tố không đúng
<root xmlns:h="http://www.w3.org/TR/html4/">
<h:table>...</h:table>
<f:table>...</f:table> <!-- Lỗi: tiền tố f chưa được khai báo -->
</root>
Kết quả: Lỗi của trình phân tích: The prefix 'f' for element 'f:table' is not bound.
GO TO FULL VERSION