2010-10-15 7 views
14

Ich möchte XML-Dokument mit Standard-Namespace, aber kein Präfix zu manipulieren. Gibt es eine Möglichkeit, Xpath ohne Namespace-URI zu verwenden, als ob es keinen Namespace gäbe?
Ich glaube, es sollte möglich sein, wenn wir die NamespaceAware-Eigenschaft von documentBuilderFactory auf false setzen. Aber in meinem Fall funktioniert es nicht.
Ist mein Verständnis falsch oder mache ich einen Fehler im Code?Wie XPath auf XML-Dokumente mit Standard-Namespace verwenden

Hier ist mein Code:

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

Hier ist meine 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

hat diese wie das gleiche Problem für eine FAQ Default XML namespace, JDOM, and XPath belwood

Antwort

21

Die XPath-Verarbeitung für ein Dokument, das den Standard-Namespace (kein Präfix) ist das gleiche wie die XPath-Verarbeitung verwendet für ein Dokument, das Präfixe verwendet:

Für Namespace-qualifizierte Dokumente können Sie einen NamespaceContext verwenden, wenn Sie den XPath ausführen. Sie müssen den Fragmenten im XPath den Namen des NamespaceContext voranstellen. Die verwendeten Präfixe müssen nicht mit den Präfixen übereinstimmen, die im Dokument verwendet werden.

Hier ist, wie es mit Ihrem Code aussieht:

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

    } 

} 

Hinweis: habe ich auch den von Dennis vorgeschlagen XPath korrigiert.

Im Folgenden auch scheint zu funktionieren, und ist näher an Ihre ursprüngliche Frage:

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 Gute Erklärung sieht. –

+0

Also muss ich in Namespace-Szenario verschieben. Nun, eine gute Idee, aber ich werde dabei sein. Ich habe Tonnen von Code, der derzeit XML ohne Namespace behandelt, durch Verwendung von Xpath. Ich musste Standard-Namespace für die Überprüfung (nach IDE und programmatisch) Zweck hinzufügen. Gibt es eine Möglichkeit, zwei Fliegen mit einer Klappe zu schlagen?Ich meine, ich muss nicht alle xpath-Ausdrücke bearbeiten und gleichzeitig das Dokument sowohl in IDE als auch programmatisch validieren lassen. – WSK

+0

Ich dachte, Namespace zu entfernen. In diesem Fall werde ich nicht mit dem XPath-Problem konfrontiert und für die programmatische Validierung kann ich Namespace zur Laufzeit hinzufügen. Vielleicht muss ich meine Dokumente nur vor der Validierung analysieren. Es könnte akzeptabel sein, aber nachdem ich dies getan habe, sehe ich keine Möglichkeit, meine XML-Dokumente durch die IDE zu validieren. Irgendeine andere Idee? – WSK

1

Blaise Doughan richtig ist, ist angebracht Code korrekt.
Problem war irgendwo elese. Ich habe alle meine Tests über Application Launcher in Eclipse IDE ausgeführt und nichts hat funktioniert. Dann entdeckte ich das Eclipse-Projekt als Ursache aller Trauer. Ich habe meine Klasse von der Eingabeaufforderung aus ausgeführt, es hat funktioniert. Habe ein neues Eclipse-Projekt erstellt und denselben Code dort eingefügt, es hat dort auch funktioniert. Danke euch allen für eure Zeit und Mühe.

0

Ich habe eine einfache NamespaceContext Implementierung geschrieben (here), die hilfreich sein könnte. Es benötigt einen Map<String, String> als Eingabe, wobei key ein Präfix ist und value ein Namespace ist.

Es folgt die NamespaceContext spesification, und Sie können sehen, wie es in der unit tests funktioniert.

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"] 

Beachten Sie, dass es eine Abhängigkeit von Google Guava