XPath: есть ли способ установить пространство имен по умолчанию для запросов? - PullRequest
12 голосов
/ 13 ноября 2009

Есть ли способ установить в 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 ]

10 голосов
/ 13 ноября 2009

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

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

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

4 голосов
/ 13 ноября 2009

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


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

2 голосов
/ 11 июня 2014

Я знаю, что этот вопрос старый, но я потратил 3 часа на поиски решения этой проблемы, и @ kdgregorys answer очень помог мне. Я просто хотел поставить именно то, что сделал, используя 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...