Выберите узел, используя xpath и jdom

У меня есть документ в формате xform

<?xml version="1.0" encoding="UTF-8"?><h:html xmlns:h="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa">
<h:head>
    <h:title>Summary</h:title>
    <model>
        <instance>
            <data vaultType="nsp_inspection.4.1">
                <metadata vaultType="metadata.1.1">
                    <form_start_time type="dateTime" />
                    <form_end_time type="dateTime" />
                    <device_id type="string" />
                    <username type="string" />
                </metadata>
                <date type="date" />
                <monitor type="string" />
            </data>
        </instance>
    </model>
</h:head>

Я хотел бы выбрать элемент данных из xform, используя xpath и jdom

XPath xpath = XPath.newInstance("h:html/h:head/h:title/");

кажется, работает нормально и выбирает элемент заголовка, но

XPath xpath = XPath.newInstance("h:html/h:head/model");

не выбирает модельный элемент. Я думаю, это как-то связано с пространством имен.

1 ответ

Решение

Несколько вещей. Вы действительно должны использовать JDOM 2.0.x ... (2.0.5 - последняя версия). XPath API в версиях 2.0.x намного лучше, чем в JDOM 1.x: см. https://github.com/hunterhacker/jdom/wiki/JDOM2-Feature-XPath-Upgrade

@wds прав в том, что не имеет правильного пространства имен для элементов xforms тоже... и именно поэтому ваш XPath работает, потому что он имеет то же пространство имен, что и элементы xhtml с префиксом 'h'. Ваш код, скорее всего, будет сломан.

Пространства имен в XPath часто путают людей, потому что каждое пространство имен в XPath должно иметь префикс. Даже если что-то является пространством имен по умолчанию в XML (без префикса, как ваш элемент 'model'), оно должно быть в XPath. запросы без префикса в XPath всегда ссылаются на пространство имен "no namespace".... (спецификация XPath: http://www.w3.org/TR/xpath/)

QName в тесте узла раскрывается в расширенное имя с использованием объявлений пространства имен из контекста выражения. Это происходит так же, как расширение для имен типов элементов в начальном и конечном тегах, за исключением того, что пространство имен по умолчанию, объявленное с помощью xmlns, не используется: если QName не имеет префикса, то URI пространства имен равен нулю (это то же самое способ расширения имен атрибутов). Ошибка, если у QName есть префикс, для которого нет никакого объявления пространства имен в контексте выражения

Предполагая, что @wds является верным, а пространство имен для элемента модели должно быть " http://www.w3.org/2002/xforms ", тогда ваше деление пространства имен в вашем документе должно быть xmlns="http://www.w3.org/2002/xforms". Но это пространство имен является пространством имен "по умолчанию", а URI для пространства имен без префикса в вашем запросе XPath - "".

Чтобы получить доступ к пространству имен http://www.w3.org/2002/xforms в вашем XPath, вы должны дать ему префикс для контекста XPath, скажем, xpns (для пространства имен xpath). В JDOM 1.x вы добавляете это пространство имен с помощью:

XPath xpath = XPath.newInstance("/h:html/h:head/xpns:model");
xpath.addNamespace(Namespace.getNamespace("xpns", "http://www.w3.org/2002/xforms");
Element model = (Element)xpath.selectSingleNode(mydoc)

Обратите внимание, как это добавляет xpns к запросу. Также обратите внимание, что я "привязал" ссылку h: / html к корню "/" документа, что повысит производительность оценки запроса.

В JDOM 2.x API-интерфейс XPath значительно лучше (хотя в некоторых случаях это может показаться излишним).

XPathFactory xpf = XPathFactory.instance();
XPathExpression<Element> xpath = xpf.compile("/h:html/h:head/xpns:model",
              Filters.element(), null,
              Namespace.getNamesace("xpns", "http://www.w3.org/2002/xforms"));
Element model = xpath.evaluateFirst(mydoc);

Узнайте больше о новом API XPath в javadoc JDOM 2.x: javadoc XPathFactory.compile(...)

Другие вопросы по тегам