HTML5ではタグを閉じなくてもよいのでjava.xmlのDocumentBuilderでそのままパースできません。
Validator.nu HTML Parserを利用するのが一番簡単です。
日本語のドキュメントが少ないのでメモを共有します。
このライブラリはFirefox4系のコアでC++にコード変換して利用されているとのことでかなり信頼性が高いと考えられます。これまでに数百のサイトのhtmlを解析してみましたがパースでエラーが出たことはまだありません。英語のドキュメントでの利用方法もそれなりに充実しています。
本投稿時点でのバージョンは1.4です。
使い方
まずは上記URLにあるzipをダウンロードしhtmlparser-1.4.jarにビルドパスを通します。
nu.validator.htmlparser.dom.DocumentBuilderクラスを利用することで簡単にorg.w3c.Documentに変換できます。
// Validator.nu HTMLParser付属のHtmlDocumentBuilderでパース
HtmlDocumentBuilder builder = new HtmlDocumentBuilder();
StringReader reader = new StringReader(body);
Document doc = builder.parse(new InputSource(reader));
// XPathの準備
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
// XPathでid=foo要素直下の文字列を取得
String path = "//*[@id='foo']/text()";
String fooString = xpath.evaluate(path,doc);
System.out.println(fooString);
// XPathでid=var要素をw3c.dom.Nodeとして取得
path = "//*[@id='var']";
Node node = (Node) xpath.evaluate(path,doc, XPathConstants.NODE);
XPathの利用方法の詳細は触れません。
既知の問題?
下記のHTMLの文字列を正確に取得できません。
<div id="foo">
hoge A
<div class="large">large B</div>
foo C
</div>
上記HTMLではXPath仕様で私の理解ではtext()で直下の文字列[hoge A foo C]が取得できるべきと思うのですが「hoge A」しか取得できません。(間違っていたらご指摘ください。)