Как использовать XPath на документах xml, имеющих пространство имен по умолчанию - PullRequest
15 голосов
/ 15 октября 2010

Я хочу манипулировать документом xml, имеющим пространство имен по умолчанию, но без префикса. Есть ли способ использовать xpath без пространства имен uri так же, как если бы пространства имен не было?
Я считаю, что это должно быть возможно, если мы установим для свойства namespaceAware documentBuilderFactory значение false Но в моем случае это не работает.
Мое понимание неверно или я делаю какую-то ошибку в коде?

Вот мой код:

    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
    domFactory.setNamespaceAware(false);
    try {
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document dDoc = builder.parse("E:/test.xml");

        XPath xPath = XPathFactory.newInstance().newXPath();
        NodeList nl = (NodeList) xPath.evaluate("//author", dDoc, XPathConstants.NODESET);
        System.out.println(nl.getLength());
    } catch (Exception e) {
        e.printStackTrace();
    }

Вот мой xml:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.mydomain.com/schema">
  <author>
    <book title="t1"/>
    <book title="t2"/>
  </author>
</root>

Ответы [ 3 ]

22 голосов
/ 15 октября 2010

Обработка XPath для документа, который использует пространство имен по умолчанию (без префикса), такая же, как обработка XPath для документа, который использует префиксы:

Для документов, квалифицированных для пространства имен, вы можете использовать NamespaceContext при выполненииXPath.Вам нужно будет поставить префикс фрагментов в XPath, чтобы они соответствовали NamespaceContext.Используемые префиксы не должны совпадать с префиксами, используемыми в документе.

Вот как это выглядит с вашим кодом:

import java.util.Iterator;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

public class Demo {

    public static void main(String[] args) {
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(true);
        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document dDoc = builder.parse("E:/test.xml");

            XPath xPath = XPathFactory.newInstance().newXPath();
            xPath.setNamespaceContext(new MyNamespaceContext());
            NodeList nl = (NodeList) xPath.evaluate("/ns:root/ns:author", dDoc, XPathConstants.NODESET);
            System.out.println(nl.getLength());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static class MyNamespaceContext implements NamespaceContext {

        public String getNamespaceURI(String prefix) {
            if("ns".equals(prefix)) {
                return "http://www.mydomain.com/schema";
            }
            return null;
        }

        public String getPrefix(String namespaceURI) {
            return null;
        }

        public Iterator getPrefixes(String namespaceURI) {
            return null;
        }

    }

}

Примечание: я также использовал исправленный XPath, предложенный Деннис .

Следующее также работает, и оно ближе к вашему первоначальному вопросу:

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

public class Demo {

    public static void main(String[] args) {
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document dDoc = builder.parse("E:/test.xml");

            XPath xPath = XPathFactory.newInstance().newXPath();
            NodeList nl = (NodeList) xPath.evaluate("/root/author", dDoc, XPathConstants.NODESET);
            System.out.println(nl.getLength());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
1 голос
/ 15 октября 2010

Блейз Дафан прав, прикрепленный код правильный.
Проблема была где-то еще.Я выполнял все свои тесты через Application Launcher в Eclipse IDE, и ничего не работало.Тогда я обнаружил, что проект Eclipse был причиной всего горя.Я запускал свой класс из командной строки, он работал.Создали новый проект Eclipse и вставили туда же код, он тоже работал.Спасибо всем, ребята, за ваше время и усилия.

0 голосов
/ 28 сентября 2015

Я написал простую реализацию NamespaceContext ( здесь ), которая может помочь.Он принимает Map<String, String> в качестве ввода, где key является префиксом, а value является пространством имен.

Он следует за NamespaceContext спецификацией, и вы можете увидеть, какон работает в модульных тестах .

Map<String, String> mappings = new HashMap<>();
mappings.put("foo", "http://foo");
mappings.put("foo2", "http://foo");
mappings.put("bar", "http://bar");

context = new SimpleNamespaceContext(mappings);

context.getNamespaceURI("foo");    // "http://foo"
context.getPrefix("http://foo");   // "foo" or "foo2"
context.getPrefixes("http://foo"); // ["foo", "foo2"]

Обратите внимание, что он зависит от Google Guava

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...