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

发布于 2024-08-16 03:27:07 字数 1278 浏览 13 评论 0原文

我有以下代码:

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

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

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

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

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

Just to clarify2 yes I know Node is an iterface, that getClass() returns a concrete class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

枫林﹌晚霞¤ 2024-08-23 03:27:07

好吧,我想通了!

如果评估方法接收到一个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

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

Ok I figured it out!

If the evaluate method receives an InputSource the above error occurs.

e.g.

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)

But if evaluate receives a 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, this is weird...

江心雾 2024-08-23 03:27:07

试试这个代码:

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

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:

Node n = NodeOverNodeInfo.wrap((NodeInfo) evaluate);
System.out.println(n.getNodeName());
System.out.println(n.getTextContent());
何必那么矫情 2024-08-23 03:27:07

有点奇怪,这个。 Saxon javadocTinyElementImpl 不实现任何 org.w3c.dom 接口,但您可以从 XPath 评估中获取它们。

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

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

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.

My guess is that Saxon eschews the standard DOM model in favour of its own one. I suspect that the XPathConstants.NODE that you pass to evaluate is really just a hint. 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.

Solution: either use the Saxon DOM types as returned, or don't use Saxon.

寻找我们的幸福 2024-08-23 03:27:07

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

编辑回应评论:

抱歉,我没有注意instanceof。查看 源代码,看来TinyNodeImpl没有实现org.w3c.dom.Node。查看 JDK 文档,似乎不必这样做: javax.xml.XPath 指的是 XPathConstants 用于结果类型,它引用“XPath 1.0 NodeSet 数据类型”(如果您查看 XPath 1.0 规范,则未定义该类型) )。

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

Node is an interface. You have to have a concrete class for implementation. And getClass() returns that concrete class.

Edit in response to comment:

Sorry, I didn't pay attention to the instanceof. Looking at the source code, it appears that TinyNodeImpl doesn't implement 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).

So, it seems that returns from the XPath API are only required to be consistent when used within that API. Not exactly what you wanted to hear, I'm sure. Can you use the built-in JDK implementation? I know that it returns org.w3c.dom objects.

雪落纷纷 2024-08-23 03:27:07

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

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

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

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

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

kdgregory is correct that Node is just an interface, and TinyElementImpl implements that interface. expression.evaluate() can't return an instance of Node, it has to return a concrete class which implements 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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文