Пространство имен XML по умолчанию, JDOM и XPath
Вопрос
Я хочу использовать 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.