Kiểm tra XPath
Kiểm tra biểu thức XPath đối với XML và xem tất cả các nút khớp
Nhập XML
XPath là gì?
XPath (XML Path Language) là ngôn ngữ truy vấn dùng để chọn các nút từ một tài liệu XML. Được W3C định nghĩa như một phần của chuẩn XSLT, XPath coi tài liệu XML như một cây nút và cung cấp cú pháp dựa trên đường dẫn để điều hướng cây đó. Một biểu thức XPath như //book[@category="fiction"]/title sẽ chọn mọi phần tử title bên trong phần tử book có thuộc tính category bằng "fiction". XPath 1.0, phiên bản được mọi trình duyệt lớn và hầu hết các thư viện XML hỗ trợ, được công bố là Khuyến nghị W3C vào năm 1999 và vẫn là phiên bản được triển khai rộng rãi nhất.
Biểu thức XPath trả về một trong bốn kiểu kết quả: node-set, chuỗi, số, hoặc boolean. Node-set là kết quả phổ biến nhất và chứa không hoặc nhiều nút XML (phần tử, thuộc tính, nút văn bản, chú thích, hoặc chỉ thị xử lý). Kết quả chuỗi, số và boolean đến từ các hàm XPath như count(), sum(), contains(), và các phép so sánh boolean. Hệ thống kiểu này làm cho XPath phù hợp cả với việc trích xuất dữ liệu lẫn viết logic điều kiện trong các stylesheet XSLT và các xác nhận XML Schema.
Biểu thức phiên bản 1.0 hoạt động ở mọi nơi: document.evaluate() trong JavaScript, lxml và ElementTree của Python, javax.xml.xpath của Java, DOMXPath của PHP, và các công cụ dòng lệnh như xmllint. Phiên bản 2.0 và 3.1 bổ sung hệ thống kiểu phong phú hơn và nhiều hàm hơn nhưng yêu cầu các engine chuyên dụng như Saxon. Hãy sử dụng phiên bản 1.0 theo mặc định. Chỉ dùng 2.0 hoặc 3.1 khi bạn cần sequence, biểu thức chính quy, hoặc hàm bậc cao — và chấp nhận phụ thuộc vào Saxon hoặc BaseX.
Tại sao sử dụng công cụ kiểm tra XPath trực tuyến?
Viết biểu thức đúng đòi hỏi phải hiểu cấu trúc tài liệu và kiểm thử với dữ liệu thực. Công cụ này cung cấp môi trường tương tác để thử nghiệm các biểu thức mà không cần thiết lập dự án hay viết mã khởi tạo.
Các trường hợp sử dụng công cụ kiểm tra XPath
Tài liệu tham khảo trục XPath
Một trục xác định hướng điều hướng tương đối với nút hiện tại (nút ngữ cảnh). Cú pháp đầy đủ là axis::node-test[predicate], mặc dù hầu hết các lập trình viên sử dụng dạng viết tắt (//, @, ..) hàng ngày. Bảng này liệt kê tất cả các trục phiên bản 1.0 với các ví dụ thực tế.
| Trục | Ví dụ | Mô tả |
|---|---|---|
| child | child::book | Direct children named "book" |
| descendant | descendant::title | All "title" elements at any depth |
| parent | parent::* | The parent of the current node |
| ancestor | ancestor::catalog | All ancestors named "catalog" |
| following-sibling | following-sibling::book | Siblings after the current node |
| preceding-sibling | preceding-sibling::book | Siblings before the current node |
| attribute | attribute::lang | The "lang" attribute of the node |
| self | self::book | The current node if it is "book" |
| descendant-or-self | //title | Shorthand: any "title" in the tree |
| ancestor-or-self | ancestor-or-self::* | Current node plus all ancestors |
Hàm XPath 1.0
Ngôn ngữ định nghĩa 27 hàm tích hợp trong bốn danh mục: node-set, chuỗi, số, và boolean. Đây là các hàm bạn sẽ sử dụng thường xuyên nhất khi viết truy vấn. Tất cả đều được công cụ này hỗ trợ và được mọi triển khai tuân thủ chuẩn hỗ trợ.
| Hàm | Danh mục | Mô tả |
|---|---|---|
| text() | Node test | Selects text content of a node |
| position() | Numeric | Returns 1-based position in node set |
| last() | Numeric | Returns size of current node set |
| count() | Numeric | Counts nodes: count(//book) |
| contains() | String | contains(@class, "active") — substring match |
| starts-with() | String | starts-with(title, "The") — prefix match |
| normalize-space() | String | Strips leading/trailing whitespace |
| string-length() | Numeric | Returns character count of a string |
| sum() | Numeric | sum(//price) — totals numeric values |
| not() | Boolean | not(@disabled) — negation |
| name() | String | Returns element or attribute name |
Ví dụ mã
Các ví dụ này cho thấy cách đánh giá biểu thức theo chương trình. Mỗi đoạn mã sử dụng cùng một cấu trúc catalog.xml để bạn có thể so sánh sự khác biệt về API giữa các ngôn ngữ.
const xml = `<catalog>
<book id="1"><title>1984</title><price>7.99</price></book>
<book id="2"><title>Dune</title><price>12.99</price></book>
</catalog>`
const parser = new DOMParser()
const doc = parser.parseFromString(xml, 'application/xml')
// Select all book titles
const result = doc.evaluate('//book/title', doc, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null)
let node = result.iterateNext()
while (node) {
console.log(node.textContent) // → "1984", "Dune"
node = result.iterateNext()
}
// Get a numeric value
const sum = doc.evaluate('sum(//price)', doc, null, XPathResult.NUMBER_TYPE, null)
console.log(sum.numberValue) // → 20.98from lxml import etree
xml = """<catalog>
<book id="1"><title>1984</title><price>7.99</price></book>
<book id="2"><title>Dune</title><price>12.99</price></book>
</catalog>"""
tree = etree.fromstring(xml.encode())
# Select elements by attribute
books = tree.xpath('//book[@id="1"]/title/text()')
print(books) # → ['1984']
# Use predicates with position
first = tree.xpath('//book[1]/title/text()')
print(first) # → ['1984']
# Boolean check
has_cheap = tree.xpath('boolean(//price[. < 10])')
print(has_cheap) # → Trueimport javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
var factory = DocumentBuilderFactory.newInstance();
var builder = factory.newDocumentBuilder();
var doc = builder.parse(new java.io.File("catalog.xml"));
var xpath = XPathFactory.newInstance().newXPath();
// Select node set
NodeList titles = (NodeList) xpath.evaluate(
"//book/title", doc, XPathConstants.NODESET
);
for (int i = 0; i < titles.getLength(); i++) {
System.out.println(titles.item(i).getTextContent());
// → "1984", "Dune"
}
// Evaluate to number
double total = (double) xpath.evaluate(
"sum(//price)", doc, XPathConstants.NUMBER
);
System.out.println(total); // → 20.98# Select all book titles xmllint --xpath '//book/title/text()' catalog.xml # → 1984Dune # Select by attribute xmllint --xpath '//book[@id="2"]/title' catalog.xml # → <title>Dune</title> # Count nodes xmllint --xpath 'count(//book)' catalog.xml # → 2 # Using xmlstarlet for formatted output xmlstarlet sel -t -v '//book/title' -n catalog.xml # → 1984 # → Dune