#java #xml #xpath #jdom-2
#java #xml #xpath #jdom-2
Вопрос:
Попытка использовать XPath с XML-файлом, который имеет пространство имен по умолчанию, объявленное для корневого узла.
Пример кода:
final SAXBuilder builder = new SAXBuilder();
final Document document = builder.build(originalFile);
final XPathFactory xFactory = XPathFactory.instance();
final String expression = String.format("//section[@label='%s']/section/section", LABEL);
final XPathExpression<Element> sectionExpression = xFactory.compile(expression, Filters.element());
final List<Element> sections = sectionExpression.evaluate(document);
Разделы пусты.
Фрагмент XML-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://www.stellent.com/sitestudio/Project/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.stellent.com/sitestudio/Project/ http://www.stellent.com/sitestudio/ss_project_schema.xsd">
<section label="Index">
<section label="xyz">
<section label="child">
...
</section>
</section>
</section>
</project>
Удаление xmlns="http://www.stellent.com/sitestudio/Project/"
работает, но не является решением!
Почему XPath не может узнать об этом пространстве имен по умолчанию? Кроме того, почему это волнует?
А еще лучше, как я могу это исправить в общем виде?
Спасибо за любую информацию.
Комментарии:
1. Обратите внимание, что XPath 2.0 позволяет вам определить пространство имен по умолчанию, которое применяется к именам элементов без префиксов в вашем выражении XPath; но XPath API по умолчанию в JDOM2 использует XPath 1.0. Если вы хотите использовать XPath 2.0 с JDOM2, вы можете сделать это с помощью движка Saxon XPath.
Ответ №1:
JDOM поступает правильно. Это часто задаваемые вопросы, и не только для JDOM, но и для XPath в целом. Спецификация XPath (в некоторой степени) ясна по этому поводу (я выделил соответствующую часть жирным шрифтом):
QName в тесте узла расширяется до расширенного имени с использованием объявлений пространства имен из контекста выражения. Таким же образом выполняется расширение для имен типов элементов в тегах start и end за исключением того, что пространство имен по умолчанию, объявленное с помощью xmlns, не используется: если QName не имеет префикса, то URI пространства имен равен null (таким же образом расширяются имена атрибутов). Это ошибка, если QName имеет префикс, для которого нет объявления пространства имен в контексте выражения.
С точки зрения XPath, это означает, что обработка пространства имен для правил в выражении XPath на самом деле не совпадает с узлами в XML. Для всех выражений XPath вам необходимо определить (дублировать) контекст пространства имен для выражения, и префиксы, которые вы используете для выражения, фактически полностью независимы от тех, которые используются в реальном XML-документе.
Вам нужно «изобрести» префикс пространства имен для вашего пространства имен по умолчанию и использовать этот префикс в вашем выражении (здесь я изобрел префикс пространства имен ns
):
final String expression = String.format("//ns:section[@label='%s']/ns:section/ns:section", LABEL);
final XPathExpression<Element> sectionExpression = xFactory.compile(expression, Filters.e, null,
Namespace.getNamespace("ns", "http://www.stellent.com/sitestudio/Project/"))
Комментарии:
1. Я все еще не до конца понимаю это .. но это работает.. спасибо! 🙂
2. Привет, @ThomasBeauvais — я провожу много времени в комнате чата 2nd monitor stack exchange . Я буду рад рассмотреть это более подробно.
3. Есть ли способ настроить это так, чтобы существовало какое-то пространство имен по умолчанию? Так что, префикс не требуется?
4. @ycomp — для XPath ответ «Нет», и это по дизайну XPath. Это несоответствие между XML и XPath, которое застало многих людей врасплох, но обойти его невозможно. Это часть спецификации XPath.
5. @rolfl спасибо, по крайней мере, теперь я это знаю.. Я провел некоторое время, ударяясь головой о клавиатуру, пытаясь разобраться в этом. Теперь я просто использую префикс из 1 буквы