#!/usr/bin/perl # ****************************************************** # Software name : HTML::TreeBuilderによるHTML整形 (XHTML対応) # # Copyright (C) INOUE Hirokazu, All Rights Reserved # http://oasis.halfmoon.jp/ # # version 1.1 (2010/March/19) # # GNU GPL Free Software # # このプログラムはフリーソフトウェアです。あなたはこれを、フリーソフトウェア財 # 団によって発行された GNU 一般公衆利用許諾契約書(バージョン2か、希望によっては # それ以降のバージョンのうちどれか)の定める条件の下で再頒布または改変することが # できます。 # # このプログラムは有用であることを願って頒布されますが、*全くの無保証* です。 # 商業可能性の保証や特定の目的への適合性は、言外に示されたものも含め全く存在し # ません。詳しくはGNU 一般公衆利用許諾契約書をご覧ください。 # # あなたはこのプログラムと共に、GNU 一般公衆利用許諾契約書の複製物を一部受け取 # ったはずです。もし受け取っていなければ、フリーソフトウェア財団まで請求してく # ださい(宛先は the Free Software Foundation, Inc., 59 Temple Place, Suite 330 # , Boston, MA 02111-1307 USA)。 # # http://www.opensource.jp/gpl/gpl.ja.html # ****************************************************** use strict; use utf8; # スクリプト内utf8処理 binmode STDOUT,":utf8"; # messagesに「Wide character in print at …」書き込み回避 # ユーザディレクトリ下のCPANモジュールを読み込む use lib '/home/tmg1136-inue/local/lib/perl5'; use CGI; # GET, POSTの処理 use File::Basename qw(basename); # 自身のスクリプト名を得るため use HTTP::Lite; use HTML::TreeBuilder; use HTML::Entities; use Encode; use Encode::Guess; use HTML::Tagset (); # 自身のスクリプト名 my $strThisScript = basename($0, ''); # デフォルトのテスト用URL my $strTestURL = "http://oasis.halfmoon.jp/cgi-bin/html-build/rebuild-simple.cgi"; # 機能のスイッチ(POSTで送信されてくる) my $boolWriteBooleanAttr = 0; my $boolRewriteAttrSmall = 0; my $boolImgAlt = 0; my $boolIndentTab = 0; my $boolDownload = 0; # デバッグ用 my $boolDebug = 0; # 属性の値を「小文字」にする属性名の配列 my @arrAttr = ( ['basefont', 'color'], ['body', 'bgcolor', 'text', 'link', 'vlink', 'alink'], ['br', 'clear'], ['div', 'align'], ['font', 'color'], ['form', 'method'], ['h1', 'align'], ['h2', 'align'], ['h3', 'align'], ['h4', 'align'], ['h5', 'align'], ['hr', 'color', 'align'], ['img', 'align'], ['input', 'type'], ['li', 'type'], ['option', 'selected', 'disabled'], ['p', 'align'], ['select', 'multiple', 'disabled'], ['table', 'align', 'bgcolor', 'bordercolor', 'bordercolorlight', 'bordercolordark', 'frame', 'rules'], ['td', 'bgcolor', 'align', 'valign', 'nowrap'], ['textarea', 'disabled', 'readonly', 'wrap'], ['th', 'bgcolor', 'align', 'valign', 'nowrap'], ['tr', 'bgcolor', 'align', 'valign'], ['ul', 'type'] ); my $q = CGI->new; # 機能スイッチの設定 if($q->param('chk_bool')){ $boolWriteBooleanAttr = 1; } if($q->param('chk_attrsmall')){ $boolRewriteAttrSmall = 1; } if($q->param('chk_imgalt')){ $boolImgAlt = 1; } if($q->param('chk_tab')){ $boolIndentTab = 1; } if($q->param('chk_debug')){ $boolDebug = 1; } if($q->param('chk_download')){ $boolDownload = 1; } &sub_print_html_header(); # ファイルアップロードされたときの処理 if($q->param('uploadfile')){ my $fi = $q->param('uploadfile'); my $strMimeType = $q->uploadInfo($fi)->{'Content-Type'}; if($strMimeType =~ /^text\//){ # ファイルの読み込み my $datBuffer = ""; my $datFile = ""; while(read($fi, $datBuffer, 2048)){ $datFile .= $datBuffer; } # ファイルへ保存 open(fo, "> upload/temp.txt") or &sub_error_exit($!); binmode(fo); print(fo $datFile); close(fo); if(!$boolDownload){ print"

一時ファイルに保存しました

\n"; } &sub_print_html(); } else{ print "

テキストファイル以外はアップロードできません

\n"; } } else{ &sub_print_inputform(); } if(!$boolDownload){ print "

 

\n

初期画面に戻る

\n"; } &sub_print_html_footer(); #一時ファイルの削除 unlink("upload/temp.txt"); exit(0); sub sub_print_html_header{ if($boolDownload){ print "Content-Type: application/octet-stream\n" . "Content-Disposition: attachment; filename=output.html\n" . "\n"; } else{ print "Content-type: text/html\n\n"; print "\n" . "\n" . "\n" . "\t\n" . "\tHTML::TreeBuilderによるHTML整形\n" . "\t\n" . "\n" . "\n" . "

HTML::TreeBuilderによるHTML整形

\n"; } } sub sub_print_html_footer{ if(!$boolDownload){ print "\n\n"; } } sub sub_print_inputform{ print "
\n" . "\n" . "
\n" . "ブール値属性を省略しない(XHTML), \n" . "属性値は英数小文字(XHTML), \n" . "imgにalt属性無い場合は補完(XHTML)
\n" . "インデントをTABで出力, \n" . "デバッグ表示, \n" . "結果をファイルとしてダウンロード\n" . "
\n" . "

読み込むファイルはあらかじめUTF-8に変換しておくと、文字化けを防げます

\n"; } sub sub_print_html{ if(!$boolDownload){ print "

整形するHTMLファイル:./upload/temp.txt

\n"; } open(fi, "< upload/temp.txt") or &sub_error_exit($!); my $body = ""; 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; # ブール値属性のハッシュ値を削除する(ハッシュ値を削除することで、省略させないようにする) if($boolWriteBooleanAttr){ *HTML::Element::boolean_attr = \%HTML::Tagset::boolean_attr; # legacy foreach my $key (keys %HTML::Element::boolean_attr){ if($boolDebug){ print "

debug(WriteBooleanAttr): boolean_attr keys=".$key.",values=".$HTML::Element::boolean_attr{$key}."

\n"; } delete $HTML::Element::boolean_attr{$key}; } } $tree->parse($body); # imgタグにalt属性が足りない場合、新規作成する if($boolImgAlt){ foreach my $node ($tree->look_down('_tag' => 'img')){ if(!defined($node->attr('alt'))){ my $strHref = " "; if(defined($node->attr('src'))){ # ファイルのベースネームのみ取り出す(指定拡張子も削除する) $strHref = basename($node->attr('src'), ('.jpg', '.jpeg', '.gif', 'png')); if($boolDebug){ print "

debug (ImgAlt): alt=".$strHref.", src=".$node->attr('src')."

\n"; } } $node->attr('alt', $strHref); } } } # 属性値を英数小文字に変換する if($boolRewriteAttrSmall){ for my $i (0 .. $#arrAttr){ for my $j (1 .. $#{$arrAttr[$i]}){ # $arrAttr[$i][0] : タグ名、$arrAttr[$i][$j] : そのタグに対する属性名 foreach my $node ($tree->look_down('_tag' => $arrAttr[$i][0])){ if(defined($node->attr($arrAttr[$i][$j]))){ if($boolDebug && $node->attr($arrAttr[$i][$j]) =~ /[A-Z]/){ print "

debug (RewriteAttrSmall): tag=".$arrAttr[$i][0].", attr=".$arrAttr[$i][$j].", value=".$node->attr($arrAttr[$i][$j])."

\n"; } $node->attr($arrAttr[$i][$j], lc($node->attr($arrAttr[$i][$j]))); } } } } } # 全てのタグと、属性を画面表示する if($boolDebug) { my @arrAllAttr; foreach my $node ($tree->look_down('_tag' => qr/.*/)){ print "

".$node->tag()." : ".$node->as_text()." : \n"; @arrAllAttr = $node->all_attr(); foreach my $strAttr (@arrAllAttr){ print $strAttr." , "; } print "

\n"; } } $tree->eof(); # HTMLソースコードを画面出力 my $strEntityChar = "<>&".pack("U", 0x81)."-".pack("U", 0x38f); # for(my $i=0x0081; $i<0x052f; $i++){ $strEntityChar .= pack("U", $i); } if($boolDownload){ if($boolIndentTab){ print $tree->as_HTML($strEntityChar, "\t", {}); } else{ print $tree->as_HTML($strEntityChar, " ", {}); } } else{ print "
\n";
		
		if($boolIndentTab){ print encode_entities($tree->as_HTML($strEntityChar, "\t", {}), '<>&'); }
		else{ print encode_entities($tree->as_HTML($strEntityChar, "  ", {}), '<>&'); }
		print "
\n"; } # ツリーを削除 $tree = $tree->delete; } sub sub_error_exit{ print "

ファイル入出力エラー (Error ID:".$_[0].")

\n"; print "

 

\n

初期画面に戻る

\n"; &sub_print_html_footer(); #一時ファイルの削除 unlink("upload/temp.txt"); exit(0); }