2009-12-31 12 views
7

Tengo el siguiente código:Saxon XPath API devuelve TinyElementImpl en lugar de 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); 

y este es el resultado ...

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

Solo para aclarar , si hago esto:

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

o

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

me siento un ClassCastException

¿Cómo puede ser eso? de acuerdo con Java 1.5 Soles API nodo y nodeset debe asignar a org.w3c.dom.Node y org.w3c.dom.NodeList respectivamente

Sólo para clarify2 Sí sé nodo es un iterface, que getClass() devuelve una clase concreta.

Respuesta

6

Ok, ¡ya lo descubrí!

Si el método de evaluación recibe un InputSource se produce el error anterior.

p. Ej.

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

Luego resultado no es la implementación de org.w3c.dom.Node (TinyElementImpl)

evaluar Pero si recibe un Node (o una 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 

Funciona, pero aún así, esto es raro ..

+0

Tiene sentido ... si pone W3C DOM, obtiene W3C DOM. De lo contrario, obtienes DOM exclusivo. – skaffman

+2

Bienvenido a Java XML. – Esko

2

Node es una interfaz. Tienes que tener una clase concreta para la implementación. Y getClass() devuelve esa clase concreta.

Editar en respuesta al comentario:

Lo sentimos, no presté atención a la instanceof. Mirando el source code, parece que TinyNodeImpl no implementa org.w3c.dom.Node. Y mirando a la documentación de JDK, parece que no tiene por qué: el doc para javax.xml.XPath que se refiere a XPathConstants para el tipo de resultado, y se refiere a la "El tipo de datos XPath 1.0 nodeset" (que, si nos fijamos en la especificación XPath 1.0, no está definida).

Por lo tanto, parece que vuelve de la API de XPath sólo están obligados a ser constante cuando se utiliza dentro de esa API. No es exactamente lo que querías escuchar, estoy seguro. ¿Puedes usar la implementación incorporada de JDK? Sé que devuelve org.w3c.dom objetos.

+0

Gracias, I' aclararé la pregunta Y sí, obtengo una ClassCastException, puedes decir que en las últimas 2 líneas del código (evalúa instanceof Node) si no es instanceof, no implementa esa interfaz, por lo que se producirá un lanzamiento de clase exceptino. –

-1

kdgregory es correcto que Node es solo una interfaz, y TinyElementImpl implementa esa interfaz. expression.evaluate() no puede devolver una instancia de Node, tiene que devolver una clase concreta que implementa nodo.

Podría ser útil señalar que se puede utilizar una instancia de TinyElementImplcomo como Node, y puede convertir fácilmente los casos de TinyElementImp a Node.

Por ejemplo, esto debería funcionar bien:

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

continuación, puede utilizar result llamando a cualquiera de los métodos de Node, y al pasar a cualquier método que acepta un Node.

+0

Lea el comentario en la respuesta de kdgregory. TinyElementImpl no implementa Node por cierto. –

+0

OK, sí, veo que hice una suposición incorrecta. Aún así, creo que el espíritu de mi respuesta aborda algunos aspectos de la pregunta en un esfuerzo honesto por ayudar. Sin embargo, puedo vivir con el voto negativo. –

2

Es un poco extraño, este. El Saxon javadoc dice que TinyElementImpl no implementa ninguna de las interfaces de org.w3c.dom, y sin embargo, de que está recibiendo de vuelta de la evaluación XPath.

Supongo que Saxon evita el modelo DOM estándar a favor del suyo propio. Sospecho que el XPathConstants.NODE que pasas al evaluate es solo una pista. Está permitido que las expresiones XPath devuelvan cualquier cosa antigua (por ejemplo, Apache JXPath usa expresiones XPath para consultar gráficos de objetos java), por lo que está permitido que Saxon devuelva sus propios tipos de DOM en lugar de los org.w3c estándar.

Solución: utilice los tipos de DOM sajones como se muestran o no use Saxon.

3

Pruebe este código:

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

Imprime:

false 
true 

El objeto devuelto es de tipo NodeInfo, por lo que necesita envolverlo como un verdadero Node, para que pueda acceder a sus métodos:

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

Esto funciona y es la respuesta más útil en la página. ¡Bien hecho! –

Cuestiones relacionadas