Использование XPath для извлечения элементов XOM из документов с ненужными пространствами имен
Я пытаюсь проанализировать HTML, возвращенный внешней системой с XOM. HTML выглядит так:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<body>
<div>
Help I am trapped in a fortune cookie factory
</div>
</body>
</html>
(На самом деле это значительно сложнее, но у него есть объявление DOCTYPE, а также объявления пространства имен и языка, и приведенный выше HTML демонстрирует ту же проблему, что и настоящий HTML.)
Что я хочу сделать, это извлечь содержимое<div>
, но объявление пространства имен, похоже, сбивает с толку XPath. Если я удаляю объявление пространства имен (вручную, из файла), следующий код находит<div>
, без проблем:
Document document = ...
Nodes divs = document.query("//div");
Но с пространством имен, возвращенныйNodes
имеет размер 0.
Хорошо, а как насчет того, чтобы я обрезал пространство имен программно?
Element rootElement = document.getRootElement();
rootElement.removeNamespaceDeclaration(rootElement.getNamespacePrefix());
... похоже, это должно работать, но ничего не делает. ИзJavadoc:
Этот метод удаляет только дополнительные пространства имен, добавленные сaddNamespaceDeclaration.
Хорошо, я подумал, я предоставлю пространство имен для запроса:
XPathContext context =
XPathContext.makeNamespaceContext(document.getRootElement());
Nodes divs = document.query("//div", context);
Размер еще ноль.
Как насчет создания контекста пространства имен вручную?
XPathContext context = context = new XPathContext(
rootElement.getNamespacePrefix(), rootElement.getNamespaceURI());
Nodes divs = document.query("//div", context);
XPathContext
конструктор взрывается с:
nu.xom.NamespaceConflictException:
XPath expressions do not use the default namespace
Итак, я ищу либо:
способ заставить этот запрос работать, илиспособ программно удалить объявления пространства имен, илиобъяснение правильного подхода, предполагая, что оба они неверны.Обновить: На основеЛев Левицкий ответ иJaxen FAQ Я придумал следующий взломать:
XPathContext context = new XPathContext(
"foo",
document.getRootElement().getNamespaceURI());
Nodes divs = document.query("//foo:div");
Это все еще кажется мне немного сумасшедшим, но я думаю, именно так Джексен хочет, чтобы ты что-то делал.
Обновление № 2: Как отмечено ниже ипо всему интернетуэто не вина Джаксена; просто XPath - это XPath.
Итак, пока этот хак работает, я все равно хотел бы отменить объявление пространства имен. Желательно, не заходя так далеко, как XSLT.