2010-10-15 59 views
14

我想操作具有默認命名空間但沒有前綴的xml文檔。有沒有辦法使用沒有命名空間URI的xpath,就像沒有命名空間一樣?
我相信它應該是可能的,如果我們將documentBuilderFactory的namespaceAware屬性設置爲false。但在我的情況下,它不起作用。
我的理解是不正確的,或者我在代碼中犯了一些錯誤?如何在具有默認命名空間的xml文檔上使用XPath

這裏是我的代碼:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); 
    domFactory.setNamespaceAware(false); 
    try { 
     DocumentBuilder builder = domFactory.newDocumentBuilder(); 
     Document dDoc = builder.parse("E:/test.xml"); 

     XPath xPath = XPathFactory.newInstance().newXPath(); 
     NodeList nl = (NodeList) xPath.evaluate("//author", dDoc, XPathConstants.NODESET); 
     System.out.println(nl.getLength()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

這裏是我的xml:

<?xml version="1.0" encoding="UTF-8"?> 
<root xmlns="http://www.mydomain.com/schema"> 
    <author> 
    <book title="t1"/> 
    <book title="t2"/> 
    </author> 
</root> 
+0

依賴這看起來像同樣的問題 Default XML namespace, JDOM, and XPath belwood 2010-10-15 05:16:54

回答

21

爲使用默認的名稱空間(無前綴)的文檔中的XPath處理是一樣的XPath處理對於使用前綴的文檔:

對於命名空間限定的文檔,您可以在執行XPath時使用NamespaceContext。您需要在XPath中爲片段添加前綴以匹配NamespaceContext。您使用的前綴不需要與文檔中使用的前綴匹配。

下面是它的外觀與您的代碼:

import java.util.Iterator; 
import javax.xml.namespace.NamespaceContext; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.xpath.XPath; 
import javax.xml.xpath.XPathConstants; 
import javax.xml.xpath.XPathFactory; 
import org.w3c.dom.Document; 
import org.w3c.dom.NodeList; 

public class Demo { 

    public static void main(String[] args) { 
     DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); 
     domFactory.setNamespaceAware(true); 
     try { 
      DocumentBuilder builder = domFactory.newDocumentBuilder(); 
      Document dDoc = builder.parse("E:/test.xml"); 

      XPath xPath = XPathFactory.newInstance().newXPath(); 
      xPath.setNamespaceContext(new MyNamespaceContext()); 
      NodeList nl = (NodeList) xPath.evaluate("/ns:root/ns:author", dDoc, XPathConstants.NODESET); 
      System.out.println(nl.getLength()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    private static class MyNamespaceContext implements NamespaceContext { 

     public String getNamespaceURI(String prefix) { 
      if("ns".equals(prefix)) { 
       return "http://www.mydomain.com/schema"; 
      } 
      return null; 
     } 

     public String getPrefix(String namespaceURI) { 
      return null; 
     } 

     public Iterator getPrefixes(String namespaceURI) { 
      return null; 
     } 

    } 

} 

注: 我也被Dennis建議修正的XPath。

下也顯得工作,更接近你原來的問題:

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.xpath.XPath; 
import javax.xml.xpath.XPathConstants; 
import javax.xml.xpath.XPathFactory; 

import org.w3c.dom.Document; 
import org.w3c.dom.NodeList; 

public class Demo { 

    public static void main(String[] args) { 
     DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); 
     try { 
      DocumentBuilder builder = domFactory.newDocumentBuilder(); 
      Document dDoc = builder.parse("E:/test.xml"); 

      XPath xPath = XPathFactory.newInstance().newXPath(); 
      NodeList nl = (NodeList) xPath.evaluate("/root/author", dDoc, XPathConstants.NODESET); 
      System.out.println(nl.getLength()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 
+1

+1很好的解釋了常見問題。 – 2010-10-15 14:13:09

+0

所以我將不得不移到命名空間的場景。那麼,一個好主意,但我會這樣做。我有大量的代碼,目前正在通過使用xpath來處理沒有命名空間的xml。我不得不添加默認命名空間進行驗證(通過IDE和編程)的目的。一箭雙鵰可以殺死兩隻鳥嗎?我的意思是我可能不需要編輯所有的xpath表達式,同時可以在IDE中以編程方式驗證文檔。 – WSK 2010-10-15 14:59:09

+0

我想刪除命名空間。在這種情況下,我不會面對xpath問題和程序性驗證,我可能會在運行時添加命名空間。也許,我只需要在驗證之前解析我的文檔。這可能是可以接受的,但這樣做後,我看不到任何方式來驗證我的XML文檔的IDE。 有沒有其他想法? – WSK 2010-10-15 15:00:52

1

Blaise Doughan是正確的,附帶的代碼是正確的。
問題在某地被選中。我在Eclipse IDE中通過應用程序啓動器運行所有測試,但沒有任何工作。然後我發現Eclipse項目是所有悲傷的原因。我從命令提示符運行我的課,它的工作。創建了一個新的eclipse項目並粘貼了相同的代碼,它也在那裏工作。 謝謝大家,你們的時間和努力。

0

我寫了一個簡單的NamespaceContext實現(here),這可能是有幫助的。它需要一個Map<String, String>作爲輸入,其中key是一個前綴,而value是一個名稱空間。

它遵循NamespaceContext分類,您可以看到它在unit tests中的工作原理。

Map<String, String> mappings = new HashMap<>(); 
mappings.put("foo", "http://foo"); 
mappings.put("foo2", "http://foo"); 
mappings.put("bar", "http://bar"); 

context = new SimpleNamespaceContext(mappings); 

context.getNamespaceURI("foo"); // "http://foo" 
context.getPrefix("http://foo"); // "foo" or "foo2" 
context.getPrefixes("http://foo"); // ["foo", "foo2"] 

注意它對Google Guava

相關問題