2009-12-31 11 views
7

Ho il seguente codice:Saxon XPath API restituisce TinyElementImpl invece di 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); 

e questo è il risultato ...

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

Giusto per chiarire , se faccio questo:

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

o

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

ottengo un ClassCastException

Come può essere? secondo i Suns Java 1.5 API NODE e serie di nodi dovrebbero mappare org.w3c.dom.Node e org.w3c.dom.NodeList rispettivamente

Solo per clarify2 Sì, lo so nodo è un iterface, che getClass() restituisce una classe concreta.

risposta

6

Ok l'ho capito!

Se il metodo di valutazione riceve un InputSource, si verifica l'errore sopra riportato.

ad es.

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

Poi risultato non sta attuando org.w3c.dom.Node (TinyElementImpl)

Ma se valutare riceve un Node (o un 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 

Funziona, ma ancora, questo è strano ..

+0

Ha senso .... se inserisci il DOM W3C, ottieni il W3C DOM. Altrimenti, ottieni il DOM proprietario. – skaffman

+2

Benvenuti in Java XML. – Esko

2

Node è un'interfaccia. Devi avere una lezione concreta per l'implementazione. E getClass() restituisce quella classe concreta.

Modifica in risposta al commento:

Mi dispiace, non ho prestato attenzione al instanceof. Guardando il source code, sembra che TinyNodeImpl non implementa org.w3c.dom.Node. Osservando i documenti JDK, sembra che non sia necessario: il documento per javax.xml.XPath fa riferimento a XPathConstants per il tipo di risultato e fa riferimento al "Tipo di dati NodeSet 1.0 XPath" (che, se si guarda la specifica XPath 1.0, non è definita).

Quindi, sembra che i ritorni dall'API XPath siano richiesti solo per essere coerenti se utilizzati all'interno di tale API. Non esattamente quello che volevi sentire, ne sono sicuro. Puoi usare l'implementazione JDK integrata? So che restituisce gli oggetti org.w3c.dom.

+0

Grazie, ho' chiarirò la domanda E sì, ottengo un ClassCastException, puoi dire che dalle ultime 2 righe del codice (valutare instanceof Node) se non è instanceof, non implementa quell'interfaccia, quindi si verificherà un cast di classe exceptino. –

-1

kdgregory è corretto che Node è solo un'interfaccia e TinyElementImpl implementa tale interfaccia. expression.evaluate() non può restituire un'istanza di Node, deve restituire una classe concreta che implementa il nodo.

Potrebbe essere utile far notare che è possibile utilizzare un'istanza di TinyElementImplcome come Node, e si può facilmente lanciare istanze di TinyElementImp-Node.

Ad esempio, questo dovrebbe funzionare bene:

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

È quindi possibile utilizzare result chiamando uno qualsiasi dei metodi di Node, e passando a qualsiasi metodo che accetta un Node.

+0

Si prega di leggere il commento sulla risposta di kdgregory. A proposito, TinyElementImpl non implementa il nodo. –

+0

OK, sì, vedo che ho fatto un'ipotesi errata. Tuttavia, penso che lo spirito della mia risposta affronti alcuni aspetti della domanda in un onesto sforzo di aiuto. Tuttavia, posso vivere con il downvote. –

2

È un po 'strano, questo. Il Saxon javadoc dice che TinyElementImpl non implementa nessuna delle interfacce org.w3c.dom, eppure le stai recuperando dalla valutazione XPath.

La mia ipotesi è che Saxon eviti il ​​modello DOM standard in favore del proprio. Sospetto che lo XPathConstants.NODE che passi a evaluate sia davvero solo un suggerimento. È consentito che le espressioni XPath restituiscano qualsiasi cosa vecchia (ad esempio, Apache JXPath utilizza le espressioni XPath per interrogare i grafici degli oggetti java), quindi è consentito a Saxon di restituire i propri tipi DOM piuttosto che quelli standard org.w3c.

Soluzione: utilizzare i tipi DOM di Saxon restituiti o non utilizzare Saxon.

3

Prova questo codice:

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

Esso stampa:

false 
true 

L'oggetto restituito è di tipo NodeInfo, quindi è necessario avvolgerlo come un vero e proprio Node, in modo da poter accedere ai suoi metodi:

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

Questo funziona ed è la risposta più utile sulla pagina. Molto bene! –