У меня есть следующий код:
// 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;
Я получаю a ClassCastException
Как это может быть? согласно узлу Java 1.5 API Солнц и НАБОРУ УЗЛОВ должен отобразиться на org.w3c.dom.Node
и org.w3c.dom.NodeList
соответственно
Только к clarify2 да я знаю, что Узел является iterface, что getClass () возвращает реальный класс.
Хорошо, я понял!
Если метод оценки получает 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
)
Но если evaluated получает 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
Это работает, но все же это странно ...
.kdgregory верно подмечено, что Node
- это всего лишь интерфейс, и TinyElementImpl
реализует этот интерфейс. expression.assess()
не может вернуть экземпляр Node
, он должен вернуть конкретный класс, который реализует node.
Может быть полезно указать, что вы можете использовать экземпляр TinyElementImpl
как в качестве Node
, и вы можете легко отбросить экземпляры TinyElementImp
в Node
.
Например, это должно работать просто отлично:
Node result = (Node) expression.evaluate(someXML, XPathConstants.NODE);
Вы можете использовать result
, вызвав любой из методов Node
, и передав его любому методу, который принимает Node
.
Node
является интерфейсом. Для реализации необходим конкретный класс. И getClass()
возвращает этот конкретный класс.
Правка в ответ на комментарий:
Извините, я не обратил внимания на экземпляр. Глядя на исходный код , кажется, что TinyNodeImpl
не реализует org.w3c.dom.Node
. И глядя на JDK-документы, кажется, что это не обязательно: документ для javax.xml.XPath ссылается на XPathConstants для типа результата, и он ссылается на "XPath 1. 0 NodeSet data type" (который, если посмотреть на спецификацию XPath 1.0, не определен).
Таким образом, кажется, что возвращаемые из XPath API данные должны быть консистентными только при использовании внутри этого API. Не совсем то, что вы хотели услышать, я уверен. Можете ли вы использовать встроенную реализацию JDK? Я знаю, что она возвращает объекты org.w3c.dom
.
Это немного странно. В Saxon javadoc говорится, что TinyElementImpl
не реализует ни один из org.w3c.dom
интерфейсов, и все же вы получаете их обратно из оценки XPath.
Думаю, что саксонцы отказываются от стандартной модели DOM в пользу своей. Подозреваю, что XPathConstants.NODE
, который вы передаете в evaluation
, на самом деле является всего лишь подсказкой. Для XPath выражений разрешено возвращать любые старые вещи (например, Apache JXPath использует XPath выражения для запроса java графиков объектов), поэтому Саксону разрешено возвращать свои собственные типы DOM, а не стандартные org.w3c
.
Решение: либо используйте саксонские типы DOM в качестве возвращаемых, либо не используйте Саксону.
.