7KB 弱の JavaScript 製 HTML パーサーを書いた
今年書いた軽量な JavaScript 製 HTML パーサーの開発の動機について。
不完全な HTML を扱うパーサー
HTML を JSON で表現した後に、操作したり HTML に書き戻したりするツールを書いています。
<p>Hello, world!</p>
↓
["P", "Hello, world!"]
このツールが依存する HTML パーサーでは、不完全な HTML を扱いたかったため、既存の jsdom や Happy DOM の採用を諦めました。DOM やブラウザのエミュレートを指向するこれらのライブラリは HTML 片を document フラグメントとして扱えず、開始タグを持たない閉じタグを捨ててしまったり、<html><head><body>
を補って完全な文書ツリーにしてしまいます。
不完全な HTML というのは、例えば次のような条件付きコメント下の文字列を取り出した際に遭遇します。閉じタグから始まるような文書片でも、よしなに扱う必要がありました。
<!--[if IE]></div><![endif]-->
結局自作が速くて有意義だった
車輪の再発明を戒める言説が耳に残っていたせいか、既存のライブラリでしばらく頑張りましたが、自作に切り替えました。
minify して僅かに 7KB 弱、トータル800行程度で、僕の用途には十分なものが出来たので、jsdom(parse5) や Happy DOM で苦労していたのが無駄に思えます。
原型は、John Resig が2006年に発表したものを、僕が正規表現不使用に書き換えた上で jQuery ライクな Virtual DOM ライブラリで使っているものをベースにしました。
因みに、このブログのテンプレートの minify にも使い続けているので、かなり信頼しています。とはいえ Blogger のテンプレートは XML 形式なので難易度は格段に下がるのですが…
- HTML を分かっている人が書いたものを対象にする
- 省略(閉じタグと属性値のクォート)を正しく扱える
- Closure Compiler で ADVANCED コンパイルする
- 正規表現を使用しない
- 時分割で実行も可能
閉じタグが省略されたケースに対応するために、省略できる要素について、子になれるタグ名のリストを持ちました。これだけで僕が用意する HTML に限っては、意図した文書ツリーが作れるようになりました。
Web 仕様に沿ったパーサーに関する情報
ブラウザや parse5 のように、パーサー仕様に厳格にしようとすると、酔っ払いがテキトーに書いた支離滅裂なタグ構造について、タグの並び替えなどのルールがあり、これを実装することになります。
本件について参考になるリンクを示します。