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

时间:2009-12-31 13:57:18

标签: java saxon java-api xpath-api

我有以下代码:

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

这就是结果......

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

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

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

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

我得到ClassCastException

怎么会这样?根据太阳队Java 1.5 API NODE和NODESET应分别映射到org.w3c.dom.Nodeorg.w3c.dom.NodeList

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

5 个答案:

答案 0 :(得分:6)

好的我明白了!

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

e.g。

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

然后结果没有实现org.w3c.dom.NodeTinyElementImpl

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

它有效,但是,这很奇怪......

答案 1 :(得分: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

返回的对象属于NodeInfo类型,因此您需要将其包装为真实的Node,以便您可以访问其方法:

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

答案 2 :(得分:2)

Node是一个界面。你必须有一个具体的实现类。 getClass()返回那个具体的类。

编辑以回应评论:

抱歉,我没注意instanceof。查看source codeTinyNodeImpl似乎未实现org.w3c.dom.Node。看一下JDK文档,它似乎没有:javax.xml.XPath的文档引用了XPathConstants作为结果类型,它引用了“XPath 1.0 NodeSet数据类型” “(如果您查看XPath 1.0规范,则未定义)。

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

答案 3 :(得分:2)

这有点奇怪,这个。 Saxon javadoc表示TinyElementImpl没有实现任何org.w3c.dom接口,但是你从XPath评估中得到它们。

我的猜测是撒克逊避开了标准的DOM模型,而选择了自己的模型。我怀疑你传递给XPathConstants.NODE的{​​{1}}实际上只是一个暗示。允许XPath表达式返回任何旧东西(例如,Apache JXPath使用XPath表达式来查询java对象图),因此Saxon允许返回自己的DOM类型而不是evaluate标准类型。

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

答案 4 :(得分:-1)

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

指出您可以将TinyElementImpl 的实例用作<{em>}作为Node可能很有用,您可以轻松地将TinyElementImp的实例投射到Node

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

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

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