Использование XPath Содержит против HTML в Java

Я извлекаю значения из HTML-страниц, используя XPath внутри java-программы, чтобы перейти к определенному тегу и иногда использовать регулярные выражения для очистки данных, которые я получаю.

После некоторых исследований я приземлился на HTML Cleaner (http://htmlcleaner.sourceforge.net/) как самый надежный способ разобрать необработанный HTML в хороший формат XML, HTML Cleaner, однако, поддерживает только XPath 1.0, и я считаю, что мне нужны такие функции, как "contains". например, в этом фрагменте XML:

<div>
  <td id='1234 foo 5678'>Hello</td>
</div>

Я хотел бы получить текст "Hello" со следующим XPath:

//div/td[contains(@id, 'foo')]/text()

Есть ли способ получить эту функциональность? У меня есть несколько идей, но я бы предпочел не изобретать колесо, если мне не нужно:

  • Если есть способ вызвать HTML Cleaner для оценкиXPath и вернуть TagNode (который я еще не нашел), я могу использовать XML-сериализатор в возвращаемом TagNode и объединить XPaths для достижения желаемой функциональности.
  • Я мог бы использовать HTML Cleaner для очистки XML, сериализации его обратно в строку и использовать его с другой библиотекой XPath, но я не могу найти хороший оценщик java XPath, который работает с строкой.
  • Используя функции TagNode, такие как getElementsByAttValue, я мог бы, по существу, воссоздать оценку XPath и вставить в функции contains с помощью String.contains

Короткий вопрос: можно ли использовать XPath для HTML внутри существующей библиотеки Java?

Ответ 1

Относительно этого:

Я мог бы использовать HTML Cleaner для очистки XML, сериализовать его обратно на string и использовать это с другой библиотекой XPath, но я не могу найти хороший java XPath-оценщик, который работает с строкой.

Это именно то, что я хотел бы сделать (за исключением того, что вам не нужно работать с строкой (см. ниже)).

Многие парсеры HTML стараются сделать слишком много. Например, HTMLCleaner неправильно/полностью реализует спецификацию XPath 1.0 (contains(например) функция XPath 1.0). Хорошей новостью является то, что вам это не нужно. Все, что вам нужно от HTMLCleaner, - это разбор неправильного ввода. После того, как вы это сделали, лучше использовать стандартные XML-интерфейсы для обработки полученного (теперь хорошо сформированного) документа.

Сначала преобразуйте документ в стандартный org.w3c.dom.Document следующим образом:

TagNode tagNode = new HtmlCleaner().clean(
        "<div><table><td id='1234 foo 5678'>Hello</td>");
org.w3c.dom.Document doc = new DomSerializer(
        new CleanerProperties()).createDOM(tagNode);

И затем используйте стандартные интерфейсы JAXP для запроса:

XPath xpath = XPathFactory.newInstance().newXPath();
String str = (String) xpath.evaluate("//div//td[contains(@id, 'foo')]/text()", 
                       doc, XPathConstants.STRING);
System.out.println(str);

Вывод:

Hello