2017-07-24 42 views
6

我試圖對maven使用的「正確」pom.xml執行一些檢索查詢。爲此,我使用JDOM的基本XPath查詢。文檔聲明單獨的空名稱空間渲染NamespaceAware結果無用

不幸的是,查詢不會返回任何結果(也不會執行簡單的後代過濾器)。我有理由相信,問題的關鍵在於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> 

可以看到一個空的命名空間定義不匹配或者"""http://www.w3.org/2000/xmlns/",其中「」是默認的No-Namespace和xmlns命名空間是默認的xmlns命名空間。

所以給予Document,當我想執行一個XPath查詢類似如下:

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 
} 

鑑於所有XPath表達式和查詢都必須是名稱空間感知的事實(比較XPathHelper的javadoc ),我非常確定,我可以通過添加所需的名稱空間聲明來實現此目的。

我已經試過各種故障的以下內容:

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 

在這一點上,我甚至不確定我在正確的點攻擊這一點。我怎樣才能讓我的XPath查詢返回結果?

注:以下更簡單的查詢不返回結果之一:在XML

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

回答

4

XPath查詢和文檔導航一般來說,需要有效使用的命名空間。

由於處理""名稱空間有所不同,因此XPath特別不遵循與常規XML文檔相同的規則。在XML文檔中,它指的是「默認」名稱空間(無名稱空間或任何通過用xmlns="...."聲明的名稱空間來覆蓋該名稱空間)。

在XPath中,但是,規則是稍有不同(見the spec - 重點礦山):

的QName在節點測試是使用命名空間聲明從擴展成一個擴展名錶達上下文。對於開始和結束標記中的元素類型名稱,除了沒有使用用xmlns聲明的默認名稱空間之外,對於元素類型名稱進行擴展的方式相同:如果QName沒有前綴,則名稱空間URI爲空

這實際上意味着什麼,即使您在XML中不需要命名空間前綴,如dependencies,但在XPath查詢中仍需要前綴。前綴可以是任何東西 - 不需要匹配XML文檔中的任何內容。因此,選擇像「NS」任意命名空間,你可以有一個查詢:

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); 

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()); 

這是可以做到的簡單