我有以下代码:
// 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.Node
和org.w3c.dom.NodeList
只是澄清2 是的我知道Node是一个iterface,getClass()返回一个具体的类。
答案 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.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
它有效,但是,这很奇怪......
答案 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 code,TinyNodeImpl
似乎未实现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
的方法。