2009-12-31 10 views
7

Ich habe den folgenden Code:Saxon XPath API gibt TinyElementImpl statt org.w3c.dom.Node

// xpath evaluates to net.sf.saxon.xpath.XPathEvaluator 
XPath xpath = XPathFactory.newInstance().newXPath(); 
XPathExpression expression = xpath.compile("/foo/bar"); 
Object evaluate = expression.evaluate(someXML, XPathConstants.NODE); 
Object evaluate2 = expression.evaluate(someXML, XPathConstants.NODESET); 

System.out.println(evaluate!=null?evaluate.getClass():"null"); 
System.out.println(evaluate2!=null?evaluate2.getClass():"null2"); 

System.out.println(evaluate instanceof Node); 
System.out.println(evaluate2 instanceof NodeList); 

und das ist das Ergebnis ...

 
class net.sf.saxon.tinytree.TinyElementImpl 
class java.util.ArrayList 
false 
false 

Nur zu klären wenn ich dies tun:

org.w3c.dom.Node node = (org.w3c.dom.Node)evaluate; 

oder

org.w3c.dom.NodeList node = (org.w3c.dom.NodeList)evaluate2; 

ich ein ClassCastException

Wie kann das sein? nach Suns Java 1.5 API NODE und nodeset zu org.w3c.dom.Node und org.w3c.dom.NodeList bzw.

Gerade clarify2 ja ich weiß Knoten ist ein iterface, dass getClass() gibt eine konkrete Klasse abbilden sollte.

Antwort

6

Ok, ich habe es herausgefunden!

Wenn die Methode evaluate eine InputSource empfängt, tritt der obige Fehler auf.

z.B.

InputSource someXML = new InputSource(new StringReader("<someXML>...</someXML>)"); 
Object result = expression.evaluate(someXML, XPathConstants.NODE); 
Node node = (Node) result; // ClassCastException 

führen dann nicht implementiert org.w3c.dom.Node (TinyElementImpl)

Aber wenn bewerten erhält eine Node (oder eine Document):

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); 
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder(); 
Document someXML = documentBuilder.parse(new InputSource(new StringReader("<someXML>...</someXML>)")); 
Object result = expression.evaluate(someXML, XPathConstants.NODE); 
Node node = (Node) result; // works 

Es funktioniert, aber immer noch, das ist seltsam .. .

+0

Macht Sinn .... Wenn Sie W3C DOM einstecken, bekommen Sie W3C DOM raus. Andernfalls erhalten Sie proprietäres DOM heraus. – skaffman

+2

Willkommen bei Java XML. – Esko

2

Node ist eine Schnittstelle. Sie müssen eine konkrete Klasse für die Implementierung haben. Und getClass() gibt diese konkrete Klasse zurück.

bearbeiten als Antwort auf Kommentar:

Sorry, ich habe nicht die Aufmerksamkeit auf die instanceof. Mit Blick auf die source code scheint TinyNodeImplorg.w3c.dom.Node nicht zu implementieren. Und wenn man sich die JDK-Dokumente anschaut, sieht es so aus, als ob das nicht der Fall wäre: Das Dokument javax.xml.XPath verweist für den Ergebnistyp auf XPathConstants und bezieht sich auf den "XPath 1.0 NodeSet-Datentyp" (der, wenn Sie sich ansehen die XPath 1.0 Spezifikation, ist nicht definiert).

Es scheint also, dass Rückgaben von der XPath-API nur konsistent sein müssen, wenn sie in dieser API verwendet werden. Nicht genau das, was du hören wolltest, da bin ich mir sicher. Können Sie die integrierte JDK-Implementierung verwenden? Ich weiß, dass es org.w3c.dom Objekte zurückgibt.

+0

Danke, ich Ich werde die Frage klären. Und ja, ich bekomme eine ClassCastException, das kann man an den letzten 2 Zeilen des Codes erkennen (evaluate instanceof Node), wenn es nicht instanceof ist, implementiert es diese Schnittstelle nicht, daher wird eine Klasse cast exceptio vorkommen. –

-1

kdgregory ist korrekt, dass Node nur eine Schnittstelle ist, und TinyElementImpl implementiert diese Schnittstelle. expression.evaluate() kann keine Instanz von Node zurückgeben, es muss eine konkrete Klasse zurückgegeben werden, die Knoten implementiert.

Es könnte nützlich sein, darauf hinzuweisen, dass Sie eine Instanz von TinyElementImplals als Node verwenden können, und Sie können Instanzen von TinyElementImp-Node leicht gegossen.

Zum Beispiel sollte dies gut funktionieren:

Node result = (Node) expression.evaluate(someXML, XPathConstants.NODE); 

Sie dann result durch eine der Methoden der Node Aufruf verwenden können, und indem sie es auf jede Methode übergeben, die ein Node akzeptiert.

+0

Bitte lesen Sie den Kommentar zu kdgregory's Antwort. TinyElementImpl implementiert Knoten übrigens nicht. –

+0

OK, ja, ich sehe, dass ich eine falsche Annahme gemacht habe. Dennoch denke ich, der Geist meiner Antwort befasst sich mit einigen Aspekten der Frage in einer ehrlichen Bemühung zu helfen. Ich kann aber mit dem Downvote leben. –

2

Es ist ein bisschen seltsam, dieser. Die Saxon javadoc sagt, dass TinyElementImpl keine der Schnittstellen org.w3c.dom implementieren, und Sie bekommen sie von der XPath-Auswertung zurück.

Meine Vermutung ist, dass Saxon das Standard-DOM-Modell zugunsten seiner eigenen meidet. Ich vermute, dass die XPathConstants.NODE, die Sie an evaluate übergeben, wirklich nur ein Hinweis ist. Es ist zulässig, dass XPath-Ausdrücke ein beliebiges altes Objekt zurückgeben (z. B. Apache JXPath verwendet XPath-Ausdrücke zum Abfragen von Java-Objektgraphen). Daher ist es für Saxon zulässig, seine eigenen DOM-Typen anstelle von org.w3c Standard-DOM-Typen zurückzugeben.

Lösung: entweder verwenden Sie die Saxon DOM-Typen als zurückgegeben, oder verwenden Sie nicht Saxon.

3

Versuchen Sie diesen Code:

Object evaluate = expression.evaluate(someXML, XPathConstants.NODE); 
System.out.println(evaluate instanceof Node); 
System.out.println(NodeOverNodeInfo.wrap((NodeInfo) evaluate) instanceof Node); 

Er druckt:

false 
true 

Das zurückgegebene Objekt ist vom Typ NodeInfo, so dass Sie es als eine echte Node wickeln müssen, so dass Sie seine Methoden zugreifen:

Node n = NodeOverNodeInfo.wrap((NodeInfo) evaluate); 
System.out.println(n.getNodeName()); 
System.out.println(n.getTextContent()); 
+0

Dies funktioniert und ist die hilfreichste Antwort auf der Seite. Gut gemacht! –