JDOM2 с XPath не работает с пространством имен

Попытка использовать 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 не может знать об этом пространстве имен по умолчанию? Кроме того, почему это заботится?

А еще лучше, как я могу это исправить?

Спасибо за любое понимание.


person Thomas Beauvais    schedule 04.07.2014    source источник
comment
Обратите внимание, что XPath 2.0 позволяет вам определить пространство имен по умолчанию, которое применяется к именам элементов без префикса в вашем выражении XPath; но API XPath по умолчанию в JDOM2 использует XPath 1.0. Если вы хотите использовать XPath 2.0 с JDOM2, вы можете сделать это через движок Saxon XPath.   -  person Michael Kay    schedule 04.07.2014


Ответы (1)


JDOM поступает правильно. Это FAQ, и не только по JDOM, но и по XPath в целом. спецификация XPath (несколько) ясна в этом отношении (я выделил жирным шрифтом соответствующую часть):

QName в тесте узла расширяется в расширенное имя с использованием объявлений пространства имен из контекста выражения. Таким же образом выполняется раскрытие имен типов элементов в начальных и конечных тегах за исключением того, что пространство имен по умолчанию, объявленное с помощью 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/"))
person rolfl    schedule 04.07.2014
comment
Я до сих пор не совсем понимаю это... но это работает... спасибо! :) - person Thomas Beauvais; 04.07.2014
comment
Привет, @ThomasBeauvais! Я провожу много времени в чате для обмена стеками 2-го монитора. С удовольствием пройдусь по ней подробнее. - person rolfl; 04.07.2014
comment
Есть ли способ настроить это, чтобы было какое-то пространство имен по умолчанию? Чтобы префикс не требовался? - person ycomp; 24.12.2016
comment
@ycomp - для XPath ответ «Нет», и это предусмотрено XPath. Это несоответствие между XML и XPath застало многих врасплох, но его никак не обойти. Это часть спецификации XPath. - person rolfl; 24.12.2016
comment
@rolfl спасибо, по крайней мере, теперь я это знаю .. Я провел некоторое время, стуча головой о клавиатуру, пытаясь понять это. Я сейчас использую префикс из 1 буквы - person ycomp; 24.12.2016