HTML::TreeBuilderを使ってHTMLファイルを整形出力するときに、ブール値属性が省略されてしまい、XHTML準拠の出力にならない。
検証コード
use utf8; # スクリプト内utf8処理
binmode STDOUT,":utf8";
use HTML::TreeBuilder;
use HTML::Entities;
use Encode;
use Encode::Guess;
my $body = "";
# ファイルからHTMLデータを読み込む
open(fi, "< sample.html") or &sub_error_exit($!);
my $datBuffer = "";
while(read(fi, $datBuffer, 2048)){
$body .= $datBuffer;
}
close(fi);
# 文字コードをUTF-8に変換する
my $encode = guess_encoding($body, qw/ euc-jp shiftjis 7bit-jis /);
$body = decode($encode->name, $body) unless (utf8::is_utf8($body));
my $tree = HTML::TreeBuilder->new;
$tree->eof();
# HTMLソースコードを画面出力
print "<pre>\n";
print encode_entities($tree->as_HTML('<>&', "\t", {}), '<>&');
print "</pre>\n";
# ツリーを削除
$tree = $tree->delete;
で、このままだと次のように、W3C XHTML規格文書 『 4.5 属性最小化 』 および 『 C.10 ブール値属性 』 に定められている条件を満たせない。
<input checked name="CheckBox1" type="checkbox" />
ではなく、規格に沿うように次のようにしなければならない
<input checked="checked" name="CheckBox1" type="checkbox" />
で、解決方法。
属性名と属性値が同じ場合、HTML::Tagset モジュールのソースコードで定義されている、次の部分のハッシュで指定されている属性名がブール値属性として認識されるようだ。
%boolean_attr = (
# TODO: make these all hashes
'area' => 'nohref',
'dir' => 'compact',
'dl' => 'compact',
'hr' => 'noshade',
'img' => 'ismap',
'input' => { 'checked' => 1, 'readonly' => 1, 'disabled' => 1 },
'menu' => 'compact',
'ol' => 'compact',
'option' => 'selected',
'select' => 'multiple',
'td' => 'nowrap',
'th' => 'nowrap',
'ul' => 'compact',
);
つまり、このハッシュを「上書き消去」してしまえば、(他に影響が出ないならば)問題解決である。
この方針に従って、実証コードを修正する。
use utf8; # スクリプト内utf8処理
binmode STDOUT,":utf8";
use HTML::TreeBuilder;
use HTML::Entities;
use Encode;
use Encode::Guess;
use HTML::Tagset ();
~ 略 ~
# 文字コードをUTF-8に変換する
my $encode = guess_encoding($body, qw/ euc-jp shiftjis 7bit-jis /);
$body = decode($encode->name, $body) unless (utf8::is_utf8($body));
my $tree = HTML::TreeBuilder->new;
# ブール値属性のハッシュ値を削除する
*HTML::Element::boolean_attr = \%HTML::Tagset::boolean_attr;
foreach my $key (keys %HTML::Element::boolean_attr){
delete $HTML::Element::boolean_attr{$key};
}
$tree->eof();
# HTMLソースコードを画面出力
print "<pre>\n";
print encode_entities($tree->as_HTML('<>&', "\t", {}), '<>&');
print "</pre>\n";
# ツリーを削除
$tree = $tree->delete;
赤で示した部分を追加している。 これで、とりあえずブール値属性が勝手に省略されないようになった。