Perl で HTML をパースするモジュール ― 2021年12月19日 23時40分
この記事は HTML アドベントカレンダーの 19 日目の分、兼 Perl アドベントカレンダーの 19 日目の分です。
Perl で HTML をパースするモジュールはいくつもあります。
HTML::Parser
そのままの名前ですね。HTML コードをパースしていき、開始タグ、終了タグ、テキストなどを認識するとそれをイベントとして知らせてくれる、プッシュ型のパーサーです。
HTML の要素の内容モデルや、ある要素のタグが省略可能かといった知識は持っていません。あくまでもタグやテキストなどの出現を知らせるだけで、文書木を構築するわけではないからです。
逐次的なパースに対応しています。HTML 文書全体を表すコードを一気に入力として与えなくてもよく、HTTP 通信中に受け取った分からパースしていくといったことが可能です。
Web 製作者の意図を汲み取ろうと努めており、「壊れた」HTML コードでもパースできます。ただし、現在の HTML 標準 (いわゆる HTML5) のパース規則には対応しておらず、現在の主要 Web ブラウザのパース結果と異なる結果になることがあります。
HTML::PullParser
HTML::Parser
をプル型のパーサーとして利用できるようにしたものです。HTML::Parser
と同じ HTML-Parser ディストリビューションに含まれています (HTML::Parser
をインストールしようとすると HTML::PullParser
もインストールされます)。
HTML::TokeParser
HTML::PullParser
を拡張し、開始タグだけを取り出す、テキストだけを取り出すといったことを簡単にできるようにしたものです。HTML::Parser
と同じ HTML-Parser ディストリビューションに含まれています。
HTML::TreeBuilder
HTML をパースし、文書木を構築してくれます。DOM にアクセスするのと似た感覚で HTML 文書を扱えます。内部的なパースには HTML::Parser
を使っています。
HTML の要素や内容モデルに関しては HTML 4 相当の知識しかないため、現在の HTML 標準に従った HTML コードを期待通りパースできないことがあります。ignore_unknown
オプションを無効にしないと HTML5 で追加された要素が無視される (パース結果の文書木に現れない) 点は、特に注意が必要です。
HTML::TreeBuilder::XML
HTML をパースし、文書木を構築してくれます。内部的なパースには libxml2 ライブラリを使っています。
一部 HTML::TreeBuilder
と同名のメソッドを持ちますが、完全に互換性があるわけではありません。
HTML::HTML5::Parser
HTML をパースし、文書木を構築してくれます。XS を使わず Pure-Perl で書かれています。
2013 年で更新が止まっているため、現在の HTML 標準には一部追従していない……と思っていたのですが、2021 年 9 月に更新されていました (この記事を書いている途中で気づきました)。現在の HTML 標準にどこまで適合しているかは未確認です。
HTML5::DOM
HTML をパースし、文書木を構築してくれます。内部的なパースには MyHTML ライブラリを使っています。
MyHTML ライブラリは開発が停止しており、後継の Lexbor ライブラリに引き継がれています。
終わりに
現在の HTML 標準に最も近いのは HTML5::DOM
だと思っていたのですが、HTML::HTML5::Parser
が更新されていくのなら今後はどうなるかわかりません。
ECMAScript 仕様の連鎖生成規則 ― 2021年12月19日 23時58分
この記事は JavaScript アドベントカレンダーの 19 日目の分です。
JavaScript の言語仕様は ECMAScript として策定されています。ECMAScript の仕様書を読んでいくにあたって注意すべき点として、連鎖生成規則 (chain production) に対する挙動の記述が省略されているかもしれないということが挙げられます。筆者は当初このことに気づかず、「この生成規則に対する Runtime Semantics が定義されていないけど、どうなっているんだろう?」と悩みました。
連鎖生成規則とは、finally
節に対する生成規則
- Finally :
- finally Block
のように、生成規則の右辺に非終端記号がひとつだけ存在するものです。終端記号はいくつあっても (ひとつもなくても) 構いません。この場合、Finally 生成規則に対する Runtime Semantics は、その右辺に存在する非終端記号 Block に対する Runtime Semantics がそのまま呼び出されるというものになります。
最近のコメント