简体   繁体   English

Saxon XPath API返回TinyElementImpl而不是org.w3c.dom.Node

[英]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

Just 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 我得到一个ClassCastException

How can that be? 怎么可能? according to Suns Java 1.5 API NODE and NODESET should map to org.w3c.dom.Node and org.w3c.dom.NodeList respectively 根据Suns Java 1.5 API NODE和NODESET应分别映射到org.w3c.dom.Nodeorg.w3c.dom.NodeList

Just to clarify2 yes I know Node is an iterface, that getClass() returns a concrete class. 只是澄清2是的我知道Node是一个iterface,getClass()返回一个具体的类。

Ok I figured it out! 好吧我明白了!

If the evaluate method receives an InputSource the above error occurs. 如果evaluate方法收到InputSource,则会发生上述错误。

eg 例如

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

Then result is not implementing org.w3c.dom.Node ( TinyElementImpl ) 然后结果没有实现org.w3c.dom.NodeTinyElementImpl

But if evaluate receives a Node (or a Document ): 但是,如果evaluate接收Node (或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, this is weird... 它有效,但仍然,这很奇怪......

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

It prints: 它打印:

false
true

The returned object is of type NodeInfo , so you need wrap it as a real Node , so you can access its methods: 返回的对象是NodeInfo类型,因此您需要将其包装为真实Node ,以便可以访问其方法:

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

Node is an interface. Node是一个接口。 You have to have a concrete class for implementation. 你必须有一个具体的实现类。 And getClass() returns that concrete class. 并且getClass()返回该具体类。

Edit in response to comment: 编辑以回应评论:

Sorry, I didn't pay attention to the instanceof. 对不起,我没注意instanceof。 Looking at the source code , it appears that TinyNodeImpl doesn't implement org.w3c.dom.Node . 查看源代码 ,看起来TinyNodeImpl没有实现org.w3c.dom.Node And looking at the JDK docs, it appears that it doesn't have to: the doc for javax.xml.XPath refers you to XPathConstants for the result type, and it refers to the "The XPath 1.0 NodeSet data type" (which, if you look at the XPath 1.0 spec, is not defined). 看一下JDK文档,它似乎没有: javax.xml.XPath的doc引用了结果类型的XPathConstants ,它引用了“XPath 1.0 NodeSet数据类型”(其中,如果你看看XPath 1.0规范,没有定义)。

So, it seems that returns from the XPath API are only required to be consistent when used within that API. 因此,似乎只有在该API中使用时,XPath API的返回才需要保持一致。 Not exactly what you wanted to hear, I'm sure. 我确定,不完全是你想听到的。 Can you use the built-in JDK implementation? 你能使用内置的JDK实现吗? I know that it returns org.w3c.dom objects. 我知道它会返回org.w3c.dom对象。

It's a bit odd, this one. 这个有点奇怪。 The Saxon javadoc says that TinyElementImpl doesn't implement any of the org.w3c.dom interfaces, and yet you're getting them back from the XPath evaluation. Saxon javadocTinyElementImpl没有实现任何org.w3c.dom接口,但是你从XPath评估中得到了它们。

My guess is that Saxon eschews the standard DOM model in favour of its own one. 我的猜测是,Saxon避开了标准的DOM模型,而选择了自己的模型。 I suspect that the XPathConstants.NODE that you pass to evaluate is really just a hint. 我怀疑你传递给evaluateXPathConstants.NODE实际上只是一个提示。 It's permitted for XPath expressions to return any old thing (for example, Apache JXPath uses XPath expressions to query java objects graphs), so it's permitted for Saxon to return its own DOM types rather than org.w3c standard ones. XPath表达式允许返回任何旧东西(例如, Apache JXPath使用XPath表达式来查询java对象图),因此Saxon允许返回自己的DOM类型而不是org.w3c标准类型。

Solution: either use the Saxon DOM types as returned, or don't use Saxon. 解决方案:要么使用返回的Saxon DOM类型,要么不使用Saxon。

kdgregory is correct that Node is just an interface, and TinyElementImpl implements that interface. kdgregory是正确的, Node只是一个接口,而TinyElementImpl实现了该接口。 expression.evaluate() can't return an instance of Node , it has to return a concrete class which implements node. expression.evaluate()不能返回Node的实例,它必须返回一个实现 node的具体类。

It might be useful to point out that you can use an instance of TinyElementImpl as as Node , and you can easily cast instances of TinyElementImp to Node . 这可能是要指出,你可以使用的实例有用TinyElementImpl Node ,您可以轻松地投的实例TinyElementImpNode

For example, this should work just fine: 例如,这应该工作得很好:

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

You can then use result by calling any of the methods of Node , and by passing it to any method which accepts a Node . 然后,您可以通过调用Node任何方法来使用result ,并将其传递给任何接受Node方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM