XPath: есть ли способ установить пространство имен по умолчанию для запросов?

Есть ли способ установить в XPath Java префикс пространства имен по умолчанию для выражений? Например, вместо: /html:html/html:head/html:title/text()"запрос может быть следующим: /html/head/title/text()

Хотя использование префикса пространства имен работает, должен быть более элегантный способ.

Пример кода, который я сейчас делаю:

Node node = ... // DOM of a HTML document
XPath xpath = XPathFactory.newInstance().newXPath();

// set to a NamespaceContext that simply returns the prefix "html"
// and namespace URI ""http://www.w3.org/1999/xhtml"
xpath.setNamespaceContext(new HTMLNameSpace());

String expression = "/html:html/html:head/html:title/text()";
String value = xpath.evaluate(query, expression);

3 ответа

Решение

К сожалению нет. Несколько лет назад говорили о том, как определить пространство имен по умолчанию для JxPath, но быстрый взгляд на последние документы не показывает, что что-то произошло. Возможно, вы захотите потратить больше времени на просмотр документов.

Если вы действительно не заботитесь о пространствах имен, вы можете проанализировать документ без них. Просто пропустите вызов, который вы в настоящее время делаете для DocumentBuilderFactory.setNamespaceAware ().

Также обратите внимание, что ваш префикс может быть любым, что вы хотите; он не должен совпадать с префиксом в экземпляре документа. Так что вы могли бы использовать h скорее, чем htmlи минимизировать визуальный беспорядок префикса.

На самом деле я не пробовал этого, но согласно документации NamespaceContext, контекст пространства имен с префиксом "" (строка emtpy) считается пространством имен по умолчанию.


Я был немного слишком быстр в этом. Оценщик XPath не вызывает NamespaceContext для разрешения префикса "", если префикс вообще не используется в выражении XPath "/html/head/title/text()". Сейчас я углубляюсь в детали XML, в которых я не уверен на 100%, но использование выражения типа "/:html/:head/:title/text()" работает с Sun JDK 1.6.0_16, и задается вопрос NamespaceContext разрешить пустой префикс (""). Это действительно правильное и ожидаемое поведение или ошибка в Xalan?

Я знаю, что этот вопрос старый, но я потратил 3 часа на поиски решения этой проблемы, и ответ @kdgregorys очень помог мне. Я просто хотел поставить именно то, что сделал, используя kdgregorys answer в качестве руководства.

Проблема в том, что XPath в java даже не ищет пространство имен, если у вас нет префикса в запросе, поэтому для сопоставления запроса с конкретным пространством имен вы должны добавить префикс к запросу. Я использовал произвольный префикс для сопоставления с именем схемы. Для этого примера я буду использовать пространство имен OP и запрос и префикс abc, Ваше новое выражение будет выглядеть так:

String expression = "/abc:html/abc:head/abc:title/text()";

Затем сделайте следующее

1) Убедитесь, что для вашего документа задано пространство имен.

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);

2) Реализовать NamespaceContext это разрешит ваш префикс. Этот я взял из другого поста на SO и немного изменил

,

public class NamespaceResolver implements NamespaceContext {

    private final Document document;

    public NamespaceResolver(Document document) {
        this.document = document;
    }

    public String getNamespaceURI(String prefix) {
        if(prefix.equals("abc")) {
            // here is where you set your namespace
            return "http://www.w3.org/1999/xhtml";
        } else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
            return document.lookupNamespaceURI(null);
        } else {
            return document.lookupNamespaceURI(prefix);
        }
    }

    public String getPrefix(String namespaceURI) {
        return document.lookupPrefix(namespaceURI);
    }

    @SuppressWarnings("rawtypes")
    public Iterator getPrefixes(String namespaceURI) {
        // not implemented
        return null;
    }

}

3) При создании объекта XPath установите свой NamespaceContext.

xPath.setNamespaceContext(new NamespaceResolver(document));

Теперь независимо от того, какой фактический префикс схемы вы можете использовать, вы можете использовать свой собственный префикс, который будет соответствовать правильной схеме. Таким образом, ваш полный код, использующий класс выше, будет выглядеть примерно так.

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);

Document document = factory.newDocumentBuilder().parse(sourceDocFile);

XPathFactory xPFactory = XPathFactory.newInstance();
XPath xPath = xPFactory.newXPath();
xPath.setNamespaceContext(new NamespaceResolver(document));

String expression = "/abc:html/abc:head/abc:title/text()";
String value = xpath.evaluate(query, expression);
Другие вопросы по тегам