Я пытаюсь проанализировать некоторый 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 Я придумал следующий хак:
XPathContext context = new XPathContext(
"foo",
document.getRootElement().getNamespaceURI());
Nodes divs = document.query("//foo:div");
Мне все еще кажется, что это немного безумно, но, думаю, Джаксен хочет, чтобы ты поступал именно так.
Обновление №2. Как указано ниже и по всему Интернет, это не вина Джаксена; это просто XPath является XPath.
Итак, хотя этот хак работает, я все же хотел бы убрать объявление пространства имен. Желательно, не доходя до XSLT.