HTML::TreeBuilder でネストが深い HTML を調べる修行

HTML::TreeBuilder で解析したとき、ネストが 4 桁になるような HTML がある。実際に HTML としてネストが深いか、というと、そうである場合とそうでない場合がある。実際にネストが深い場合というのは、本当に center タグが延々と掘られていたり、font タグが延々ネストしていたりする。ブラウザが解釈した DOM を見ても確かにネストが深くなっている。一方で、閉じタグが省略されているケースなど、ブラウザは適当なところで閉じタグを生成して解釈しているのに対し、HTML::TreeBuilder が生真面目にネストしていると解釈してしまっている場合がある。両者の見極めがなかなか難しい。

とりあえず、深い階層の末端近くでどのようなタグが付けられているのかを調べるスクリプトを書いてみた。

use strict;
use warnings;
use Encode;
use HTML::TreeBuilder;
use Path::Class;

sub tags {
    my $node = shift;
    my $t = $node->{_tag};
    for (0..10) {
        $node = $node->parent;
        $t = $node->{_tag} . "/$t";
    }
    return $t;
}

my $file = file(shift @ARGV);
my $buffer = decode_utf8($file->slurp);
my $tree = new HTML::TreeBuilder;
$tree->parse($buffer);
$tree->eof;
my $max = -1;
$tree->look_down(sub { if ((my $d = $_[0]->depth) > $max) { $max = $d}; 0; });
print $tree->depth, ' ', $max, "\n";
my @deepest = $tree->look_down(sub { $_[0]->depth >= $max });
my %nodes = ();
foreach my $deepest (@deepest) {
    print tags($deepest), "\n";
}
__END__

もっとも深いノードの深さを求めるのに、最初は再帰的な関数を作っていたけれど、look_down メソッドを使えば簡単にできるかも、とやってみたらできた。
もっとも深いノード X の 10 個上のノードから X まで、タグを連結して表示している。