Saxon XPath API returns TinyElementImpl instead of org.w3c.dom.Node

I have the following code:

// 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); 

and this is the result ...

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

To clarify if I do this:

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

or

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

I get a ClassCastException

How can it be? according to Suns Java 1.5, the NODE and NODESET APIs must map to org.w3c.dom.Node and org.w3c.dom.NodeList respectively

For clarification only 2 yes. I know that NODE is an iteration that getClass () returns a specific class.

+7
java java-api saxon
source share
5 answers

Ok, I get it!

If the evaluation method receives an InputSource, the error above occurs.

eg.

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

Then the result does not implement org.w3c.dom.Node ( TinyElementImpl )

But if the score is Node (or a 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 

It works, but still it's weird ...

+6
source share

Try this code:

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

He prints:

 false true 

The returned object is of type NodeInfo , so you need to wrap it as a real Node so that you can access its methods:

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

Node is an interface. You must have a specific class to implement. And getClass() returns this particular class.

Edit in response to comment:

Sorry, I did not pay attention to the instance. Looking at the source code , it seems that TinyNodeImpl does not implement org.w3c.dom.Node . And looking at the JDK docs, it seems like this is not needed: the doc for javax.xml.XPath refers to the XPathConstants for the result type, and it refers to the data type like XPath 1.0 NodeSet (which, if you look at the XPath 1.0 specification, is not is defined).

So, it seems that returning from the XPath API is only required for consistency when used in this API. I'm not sure what you wanted to hear. Can you use the built-in JDK implementation? I know that it returns org.w3c.dom objects.

+2
source share

This is a little strange, this one. Saxon javadoc says that TinyElementImpl does not implement any of the org.w3c.dom interfaces, and yet you return them from XPath Score.

I suggest that Saxon avoids the standard DOM model in favor of its own. I suspect that the XPathConstants.NODE that you pass to evaluate is actually just a hint. It allowed XPath expressions to return any old thing (for example, Apache JXPath uses XPath expressions to query plots of Java objects), so it is allowed for Saxon to return its own DOM types, not standard org.w3c .

Solution: Use Saxon-returned DOM types or do not use Saxon.

+2
source share

kdgregory is correct that Node is just an interface, and TinyElementImpl implements this interface. expression.evaluate() cannot return an instance of Node , it must return a specific class that implements node.

It might be useful to indicate that you can use an instance of TinyElementImpl as a Node , and you can easily display instances of TinyElementImp in a Node .

For example, this should work fine:

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

You can then use result by calling any of the Node methods and passing it to any method that accepts Node .

-one
source share

All Articles