2017-07-24 13 views
6

Tôi đang cố thực hiện một số truy vấn truy xuất trên tệp pom.xml "đúng" được sử dụng bởi maven. Đối với điều đó tôi sử dụng các truy vấn XPath cơ bản từ JDOM.Tài liệu tuyên bố hiển thị vùng tên trống rỗng riêng biệt Không gian tên Kết quả phần mềm độc hại vô dụng

Thật không may là các truy vấn không trả về bất kỳ kết quả nào (và cũng không làm các bộ lọc con cháu đơn giản). Tôi khá chắc chắn rằng vấn đề nằm trong phần khai báo thư mục gốc của pom.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 
<!-- content --> 
</project> 

Như có thể thấy một trống-không gian tên được định nghĩa rằng không phù hợp với một trong hai "" hoặc "http://www.w3.org/2000/xmlns/", trong đó "" là Không gian tên mặc định và không gian tên xmlns là không gian tên xmlns mặc định.

Vì vậy, cho một Document, khi tôi muốn thực hiện một XPath Query như sau:

XPathBuilder<Element> depQueryBuilder = new XPathBuilder<>("//dependencies/dependency", Filters.element()); 
XPathExpression<Element> depQuery = depQueryBuilder.compileWith(XPathFactory.instance()); 

for (Element elem : depQuery.evaluate(document)) { 
    // basically unreachable, since the resultset is always empty 
} 

Với thực tế là tất cả các biểu thức XPath và các truy vấn bắt buộc phải được namespace biết (so sánh javadoc XPathHelper), Tôi khá chắc chắn rằng tôi có thể làm điều này để làm việc bằng cách thêm các khai báo không gian tên cần thiết.

Tôi đã thử những điều sau đây với các loại khác nhau của thất bại:

depQueryBuilder.setNamespace("", document.getRootElement().getAttributeValue("xmlns")); 
// NPE: Null URI 
depQueryBuilder.setNamespace("", "http://maven.apache.org/POM/4.0.0"); 
// Cannot set a Namespace URI in XPath for "" prefix 
depQueryBuilder.setNamespace(Namespace.NO_NAMESPACE); 
// no error-message, but no results either 
depQueryBuilder.setNamespace(document.getRootElement().getNamespace("xmlns")); 
// NPE: Null Namespace 
depQueryBuilder.setNamespace(document.getRootElement().getNamespace("")); 
// Cannot set a Namespace URI in XPath for "" prefix 
depQueryBuilder.setNamespace("xmlns", "http://maven.apache.org/POM/4.0.0"); 
// Name "xmlns" is not legal for JDOM/XML Namespace prefix 

Tại thời điểm này tôi thậm chí không chắc rằng tôi đang tấn công này tại thời điểm đúng. Làm thế nào tôi có thể nhận được truy vấn XPath của tôi để trả về kết quả?

Lưu ý: Các truy vấn đơn giản hơn sau đây không trả lại kết quả một trong hai:

document.getRootElement().getDescendants(Filter.element("dependency")); 
// empty iterator 
document.getRootElement().getChild("dependencies").getChildren("dependency")); 
// NullPointerException because there is no child "dependencies" 

Trả lời

4

truy vấn XPath, và chuyển hướng tài liệu nói chung trong XML, yêu cầu sử dụng hợp lệ Namespaces.

Đặc biệt XPath không tuân theo các quy tắc tương tự như tài liệu XML thông thường vì có sự khác biệt trong việc xử lý không gian tên "". Trong tài liệu XML, nó đề cập đến không gian tên "mặc định" (hoặc không có không gian tên hoặc bất cứ điều gì đã ghi đè điều đó bằng cách được khai báo với xmlns="....").

trong XPath, tuy nhiên, các quy tắc hơi khác nhau (xem the spec - nhấn mạnh tôi):

Một QName trong các thử nghiệm nút được mở rộng sang một mở rộng tên tuổi sử dụng tờ khai namespace từ ngữ cảnh biểu thức. Đây là cùng một cách mở rộng được thực hiện cho tên loại phần tử trong thẻ bắt đầu và kết thúc ngoại trừ không gian tên mặc định được khai báo với xmlns không được sử dụng: nếu QName không có tiền tố, thì URI không gian tên rỗng là

Điều này có nghĩa là thực tế, mặc dù bạn không cần tiền tố không gian tên trong XML cho những thứ như dependencies, bạn vẫn cần tiền tố trong truy vấn XPath. Tiền tố có thể là bất kỳ thứ gì - không cần phải khớp với bất kỳ thứ gì trong tài liệu XML.Vì vậy, lựa chọn một không gian tên tùy ý như 'ns', bạn có thể có một truy vấn:

XPathBuilder<Element> depQueryBuilder = new XPathBuilder<>("//ns:dependencies/ns:dependency", Filters.element()); 
depQueryBuilder.setnamespace("ns", "http://maven.apache.org/POM/4.0.0"); 
XPathExpression<Element> depQuery = depQueryBuilder.compileWith(XPathFactory.instance()); 

Điều này có thể được thực hiện đơn giản hơn với:

Namespace ns = Namespace.getNamespace("ns", "http://maven.apache.org/POM/4.0.0"); 
XPathExpression<Element> depQuery = XPathFactory.instance() 
    .compile("//ns:dependencies/ns:dependency", Filters.element(), null, ns); 
Các vấn đề liên quan