8

我有以下代码:

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

这就是结果......

类 net.sf.saxon.tinytree.TinyElementImpl
类 java.util.ArrayList
错误的
错误的

只是为了澄清,如果我这样做:

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

或者

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

我得到一个ClassCastException

怎么可能?根据 Suns Java 1.5 API NODE 和 NODESET 应该分别映射到org.w3c.dom.Nodeorg.w3c.dom.NodeList

只是为了澄清2是的,我知道 Node 是一个 iterface,getClass() 返回一个具体的类。

4

5 回答 5

7

好的,我想通了!

如果评估方法接收到 InputSource,则会发生上述错误。

例如

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

然后结果没有实现org.w3c.dom.Node( TinyElementImpl)

但是如果评估收到一个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

它有效,但这仍然很奇怪......

于 2009-12-31T14:54:29.283 回答
3

试试这个代码:

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

它打印:

false
true

返回的对象是 type NodeInfo,所以你需要把它包装成一个 real Node,这样你就可以访问它的方法:

Node n = NodeOverNodeInfo.wrap((NodeInfo) evaluate);
System.out.println(n.getNodeName());
System.out.println(n.getTextContent());
于 2010-11-04T09:35:44.153 回答
2

Node是一个接口。你必须有一个具体的类来实现。并getClass()返回那个具体的类。

编辑以回应评论:

抱歉,我没有关注instanceof。查看源代码,似乎TinyNodeImpl没有实现org.w3c.dom.Node。并且查看 JDK 文档,它似乎没有必要:javax.xml.XPath的文档将您引向 XPathConstants作为结果类型,它指的是“XPath 1.0 NodeSet 数据类型”(其中,如果您查看 XPath 1.0 规范,则未定义)。

因此,似乎只有在该 API 中使用时,来自 XPath API 的返回值才需要保持一致。不完全是你想听到的,我敢肯定。你可以使用内置的JDK实现吗?我知道它返回org.w3c.dom对象。

于 2009-12-31T14:05:58.913 回答
2

有点奇怪,这个 Saxon javadoc说它TinyElementImpl没有实现任何接口,org.w3c.dom但是您正在从 XPath 评估中获取它们。

我的猜测是,Saxon 避开了标准的 DOM 模型,转而使用了自己的模型。我怀疑XPathConstants.NODE您传递给evaluate的 确实只是一个提示。允许 XPath 表达式返回任何旧的东西(例如,Apache JXPath使用 XPath 表达式来查询 java 对象图),因此允许 Saxon 返回其自己的 DOM 类型而不是org.w3c标准类型。

解决方案:要么使用返回的 Saxon DOM 类型,要么不使用 Saxon。

于 2009-12-31T14:31:08.863 回答
-1

kdgregory 是正确的,Node它只是一个接口,并TinyElementImpl实现了该接口。expression.evaluate()不能返回 的实例Node,它必须返回实现节点的具体类。

指出您可以使用TinyElementImpl as as的实例可能很有用Node,并且您可以轻松地将实例转换为TinyElementImpto Node

例如,这应该可以正常工作:

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

然后,您可以result通过调用 的任何方法Node并将其传递给任何接受 的方法来使用Node.

于 2009-12-31T14:12:30.540 回答