Perl で構文解析はどこまで可能なのか?(HTMLを課題とする)

[上に] [前に] [次に]
びーだま [E-Mail] 2000/03/12(日) 11:11:41
Perl でどこまで構文解析が可能なのか?
行指向の処理系である Perl では複数行(多数空改行含む)の構文解析
は、難関(あるいは不可能)とされています。
ただ、Perl はおそらく地球上で最も強力な正規表現処理のできる
ツールですから、複数行処理が不可能ならば、単純には1行にしてしまえば、
かなり高度な解析は可能と考えられます。
ただ、もっとスマートな方法はあるような気がしてなりません。

そこで、HTMLタグの処理方法についてスレッドが別に立ち上がっていますが、
ここでは、HTMLタグの解析に絞って課題をつくり、その解決法を
見つけたいと思います。

課題1.ある要素のタグを抽出してその属性と、属性値に関して処理し
許可できるパターンとなったらそれを許可するような処理は可能か?


課題2.閉じタグの必要な要素を適当な場所で閉じ直す処理は可能か?

課題3.<TABLE> の一連のタグ構造の文法処理は可能か?

zizz... [HomePage] 2000/03/12(日) 15:33:28
どちらかといえばPerl嫌いな私が手を出す話題ではないでしょうが、
CPANにHTML関連のモジュールがあります。
この辺りを使って何とかなりませんか?
http://www.ring.gr.jp/archives/lang/perl/CPAN/doc/wwwman/libwww/lib/HTML/

Nick-IB 2000/03/12(日) 18:33:02
構文解析とまではいきませんが

・許可したタグ以外は特殊文字をエスケープし無効化
・タグの開閉や入れ子構造をチェック
・複数行にまたがるタグも認識

くらいの事でしたら、手前で改造した掲示板内でやってます。
http://206.253.222.116/nick-ib/test/minibbs.cgi

前のスレッドでスタイルシート云々てなお話がありましたので
「/\sstyle\s*=/i」で引っかかる怪しい記述も、問答無用で
排斥してみましたがいかがでしょう?

javascript絡みの方は未だ手付かず…。

Ichi [E-Mail] [HomePage] 2000/03/13(月) 05:47:19
>複数行(多数空改行含む)の構文解析
単純に、タグの中の改行はスペースに変換し、内容(content)中の改行は
<br>(またはスペース)に変換するとできますよね。
HTMLでは改行はデリミタ以上の役割はない...ですよね?

../200003/00030086.htm
の私の方法(タグをスタックする)を応用したとして、
(私のサイトでそのスクリプトは公開されています)

>課題2.閉じタグの必要な...
は構造上簡単に出来ます。(閉じタグが無い時の処理を変えれば良い)

>課題3.<TABLE> の一連のタグ構造の文法処理は可能か?
これも、直前の開始タグが保存されているので、
1.<tr>, <colgroup>等は<table>直下にしか置けない
2.<td>は<table>直下にしか置けない
という処理で行けると思います。

>課題1.ある要素のタグを抽出してその属性と...
さて、これが一番難しい。
>while (m/<(\/|)(\w*)/) {
while (m/<(\/|)(\w*) ([^>])/ {
で$3をサブルーチンに丸投げしましょう。
これでサブルーチンには属性と属性値が渡りました。
(Attr=Value Attr=Value)
""中に>があった場合は後々エラーになるはず。
ちゃんと&gt;と書かないと受け付けないようにしましょう。

サブルーチンは続きで...

Ichi 2000/03/13(月) 06:04:06
>2.<td>は<table>直下...
<td>は<tr>直下...
# うーん、<tr>は本来<tbody>, <tfoot>, <thead>直下だ。

Ichi 2000/03/13(月) 06:56:47
こんな感じで。

# 許可されるスタイル
$AllowedAttrs = 'size|border|title';
$IllegalAttr = '不正な属性';

sub MyAbort
{
 local($_) = shift;
 
 print "Content-type: text/plain\n\nエラー: $_";
}

sub CheckAttr
{
 local($Attrs) = shift;
 local($value,$tmp);

 while ($Attrs =~ m/([^=])=/) {
# $1が属性名
  &MyAbort($IllegalAttr) if $1 =~ m/($AllowedAttr)/io;

# $'が(スペース)+属性値+スペース...となる  
  $_ = $';
# 最初のスペースを削除
  1 while s/^ //go;
# 引用符つきの場合
  if (m/(^['"])/o) {
   $tmp = $1;
   &MyAbort($IllegalAttr) if !($' =~m/$tmp/);
   $value = $`;
   $Attrs = $';
   &MyAbort($IllegalAttr) if ($' =~ m/^['"]/o);
  }
$ 引用符なしの場合
  else {
   &MyAbort($IllegalAttr) if !m/ /o;
   $value = $`;
   $Attrs = $';
  }
  &CheckAttrValue($value);
 }
}

sub CheckAttrValue
{
 (未実装);
}

Ichi 2000/03/13(月) 06:57:40
>&MyAbort($IllegalAttr) if $1 =~ m/($AllowedAttr)/io;
&MyAbort($IllegalAttr) if $1 =~ m/($AllowedAttrs)/io

Fuji.♪ [E-Mail] [HomePage] 2000/03/13(月) 12:51:28
Ichiさん:
細かくやるなら、DOCTYPE宣言に対応したDTDを読み込んで解析するのがいいのでは。(つらい)
trがthead、tfoot、tbody直下に入るのはHTML 4.0以降で、HTML 3.2以前は問題ないですし、開始タグ、終了タグの省略可不可も考慮するべきでしょうし。(ここまで考慮したらかなりつらいことになりますが (^^;;;)

Ichi 2000/03/14(火) 05:23:37
今回の私のポリシーは掲示板のタグ制限ですので、それが出来る程度にしかやっていません。
怪しいのは全てはねています。

>DOCTYPE宣言に対応したDTDを読み込んで解析する
のは、Another HTML-lint辺りがすでにやっていますし。

>trがthead、tfoot、tbody直下に入るのはHTML 4.0以降で、HTML 3.2以前は問題ない
あ、そうなんですか。HTML 4.0しか本気で勉強したことないので、間違いました。

>開始タグ、終了タグの省略可不可も考慮するべきでしょうし。
終了タグはいいとしても、開始タグの補完は辛いですね。

Ichi 2000/03/14(火) 05:27:07
でも、名前と属性名と属性値の分離は出来たので、もっと
推し進めて行けば(これが大変なのだが)、厳密なチェックが
できるのではないかと思います。

# でもDTDは読みこむ時点で、これまた構文解析しなきゃならないしなぁ
# 辛いよなぁ

[上に] [前に] [次に]