Вопрос

Я хочу использовать JDOM для чтения XML-файла, а затем использовать XPath для извлечения данных из документа JDOM.Объект Document создается нормально, но когда я использую XPath для запроса списка элементов в документе, я ничего не получаю.

Мой XML-документ имеет пространство имен по умолчанию, определенное в корневом элементе.Самое смешное, что когда я удаляю пространство имен по умолчанию, оно успешно выполняет запрос XPath и возвращает нужные мне элементы.Что еще мне нужно сделать, чтобы мой запрос XPath возвращал результаты?

XML:

<?xml version="1.0" encoding="UTF-8"?>
<collection xmlns="http://www.foo.com">
<dvd id="A">
  <title>Lord of the Rings: The Fellowship of the Ring</title>
  <length>178</length>
  <actor>Ian Holm</actor>
  <actor>Elijah Wood</actor>
  <actor>Ian McKellen</actor>
</dvd>
<dvd id="B">
  <title>The Matrix</title>
  <length>136</length>
  <actor>Keanu Reeves</actor>
  <actor>Laurence Fishburne</actor>
</dvd>
</collection>

Джава:

public static void main(String args[]) throws Exception {
    SAXBuilder builder = new SAXBuilder();
    Document d = builder.build("xpath.xml");
    XPath xpath = XPath.newInstance("collection/dvd");
    xpath.addNamespace(d.getRootElement().getNamespace());
    System.out.println(xpath.selectNodes(d));
}
Это было полезно?

Решение

XPath 1.0 не поддерживает концепцию пространства имен по умолчанию (XPath 2.0 делает).Любой тег без префикса всегда считается частью пространства имен без имени.

Когда используешь XPath 1.0 вам нужно что-то вроде этого:

public static void main(String args[]) throws Exception {
    SAXBuilder builder = new SAXBuilder();
    Document d = builder.build("xpath.xml");
    XPath xpath = XPath.newInstance("x:collection/x:dvd");
    xpath.addNamespace("x", d.getRootElement().getNamespaceURI());
    System.out.println(xpath.selectNodes(d));
}

Другие советы

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

for (Element el : doc.getRootElement().getDescendants(new ElementFilter())) {
    if (el.getNamespace() != null) el.setNamespace(null);
}

После удаления всех пространств имен я смог использовать простой getChild("имя_эла") стиль навигации или простые запросы XPath.

Я бы не рекомендовал этот метод в качестве общего решения, но в моем случае он определенно оказался полезным.

Вы также можете сделать следующее

/*[local-name() = 'collection']/*[local-name() = 'dvd']/

Здесь список полезных запросов XPath.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top