[インデックス 15196] ファイルの概要
このコミットでは、Go言語の実験的パッケージである src/pkg/exp/html
および src/pkg/exp/html/atom
ディレクトリとその配下の全ファイルが削除されました。これは、これらのパッケージがGoのメインリポジトリから go.net
サブモジュールへ移動されたことによるものです。具体的には、HTMLパーサー、HTML要素のアトム化、関連するテストデータなど、HTML処理に関する広範なコードベースが削除されています。
削除された主なファイル群は以下の通りです。
src/pkg/exp/html/atom/atom.go
src/pkg/exp/html/atom/atom_test.go
src/pkg/exp/html/atom/gen.go
src/pkg/exp/html/atom/table.go
src/pkg/exp/html/atom/table_test.go
src/pkg/exp/html/const.go
src/pkg/exp/html/doc.go
src/pkg/exp/html/doctype.go
src/pkg/exp/html/entity.go
src/pkg/exp/html/entity_test.go
src/pkg/exp/html/escape.go
src/pkg/exp/html/example_test.go
src/pkg/exp/html/foreign.go
src/pkg/exp/html/node.go
src/pkg/exp/html/node_test.go
src/pkg/exp/html/parse.go
src/pkg/exp/html/parse_test.go
src/pkg/exp/html/render.go
src/pkg/exp/html/render_test.go
src/pkg/exp/html/testdata/
(多数のテストデータファイル)src/pkg/exp/html/token.go
src/pkg/exp/html/token_test.go
合計68ファイルが変更され、28796行が削除されています。
コミット
commit 37d92d251b167dce560937d56d44f3db71e290ed
Author: Nigel Tao <nigeltao@golang.org>
Date: Mon Feb 11 11:56:49 2013 +1100
exp/html, exp/html/atom: delete, as they're moving to the go.net
sub-repo.
The matching change is at https://golang.org/cl/7310063
The rationale was discussed at
https://groups.google.com/d/topic/golang-nuts/Qq5hTQyPuLg/discussion
R=adg, dave
CC=golang-dev
https://golang.org/cl/7317043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/37d92d251b167dce560937d56d44f3db71e290ed
元コミット内容
exp/html, exp/html/atom: delete, as they're moving to the go.net
sub-repo.
The matching change is at https://golang.org/cl/7310063
The rationale was discussed at
https://groups.google.com/d/topic/golang-nuts/Qq5hTQyPuLg/discussion
R=adg, dave
CC=golang-dev
https://golang.org/cl/7317043
変更の背景
このコミットの主な背景は、Go言語の標準ライブラリにおけるAPIの安定性と、exp/html
パッケージが持つHTML5パーシングの複雑性および進化の速さとの間のトレードオフにあります。
exp/html
パッケージは、HTML5の仕様に準拠したパーサーを提供することを目的としていました。しかし、HTML5の仕様は非常に複雑であり、常に進化しています。もしこのパッケージがGoの標準ライブラリに直接昇格した場合、Go 1.xの互換性保証の対象となり、そのAPIは凍結される必要がありました。これは、将来的な仕様変更への対応や、より高度な機能(例えば、ブラウザのような複雑なユースケースに対応するためのDOM操作、レンダリング、スクリプト処理、インクリメンタルパーシング、文字エンコーディングなど)の追加を困難にする可能性がありました。
Google Groupsでの議論によると、exp/html
はウェブスクレイピングのような「静的な」用途には適していましたが、より包括的な機能へと発展させるためには、APIの柔軟な変更が必要であるという認識がありました。go.net
サブモジュールは、標準ライブラリとは独立した開発サイクルを持つため、APIの安定性を気にすることなく、より自由に実験的な開発やAPIの洗練を行うことが可能です。
このような背景から、Nigel Tao氏(コミット著者)は、exp/html
パッケージをGoのメインリポジトリから code.google.com/p/go.net/html
へ移動することを決定しました。これにより、Go 1.0とGo 1.1の間で標準ライブラリのhtml
パッケージにAPIの差異が生じることを避けつつ、go.net
版では引き続き開発を進めることができるようになりました。この決定は、APIの正確性と完全性に対する信頼を得るために、go.net
での開発期間が必要であるというコミュニティの合意に基づいています。
前提知識の解説
Go言語の exp
パッケージ
Go言語の標準ライブラリには、exp
(experimental) というプレフィックスを持つパッケージが存在することがありました。これらのパッケージは、Goの将来のリリースで標準ライブラリに組み込まれる可能性のある、実験的な機能やAPIを提供するために使用されます。exp
パッケージは、まだAPIが安定しておらず、将来的に変更される可能性があることを示唆しています。開発者はこれらのパッケージを試用し、フィードバックを提供することで、その後の標準ライブラリへの昇格プロセスに貢献します。しかし、exp
パッケージは、その性質上、APIの互換性が保証されないため、本番環境での使用には注意が必要です。
go.net
サブパッケージ (Goの外部リポジトリ)
Go言語のエコシステムでは、標準ライブラリとは別に、golang.org/x/
以下に様々な外部リポジトリ(サブパッケージ)が存在します。go.net
(現在は golang.org/x/net
) もその一つで、ネットワーク関連の実験的なパッケージや、標準ライブラリには含まれないが有用な機能を提供します。これらの外部リポジトリのパッケージは、標準ライブラリの厳格な互換性保証の制約を受けないため、より迅速な開発やAPIの変更が可能です。exp
パッケージが標準ライブラリに昇格する前に、go.net
のような外部リポジトリで十分に成熟させ、コミュニティからのフィードバックを得るという開発プロセスが取られることがあります。
HTML5パーシングの複雑性
HTML5の仕様は、ウェブブラウザがHTMLドキュメントをどのように解析し、DOMツリーを構築するかについて非常に詳細かつ厳密に定義されています。この仕様は、単に整形式のXMLを解析するのとは異なり、不完全なHTML、誤ったHTML、古いHTMLなど、現実世界のあらゆる種類の「壊れた」HTMLを許容し、それらを一貫した方法で処理することを要求します。
例えば、HTML5パーシングには以下のような複雑な側面があります。
- エラー回復 (Error Recovery): 不正なHTML構造に対しても、ブラウザはエラーを報告するだけでなく、可能な限りDOMツリーを構築し続ける必要があります。これは、特定のトークンや要素が予期しない場所に出現した場合に、パーサーがどのように状態を遷移させるかという複雑なルールを伴います。
- コンテキスト依存の解析: 同じタグであっても、そのタグが出現するコンテキスト(親要素、現在の挿入モードなど)によって解析ルールが変化することがあります。
- 特殊要素の処理:
<script>
,<style>
,<textarea>
,<title>
などの要素は、その内容が通常のHTMLとは異なる方法で解析される(例えば、生のテキストとして扱われる)ため、特別な処理が必要です。 - アトム化 (Atomization): HTMLのタグ名や属性名など、頻繁に出現する文字列を効率的に処理するために、それらを一意の整数値(アトム)にマッピングする技術が用いられます。これにより、文字列比較の代わりに高速な整数比較が可能になり、メモリ使用量も削減できます。
これらの複雑性のため、堅牢で正確なHTML5パーサーを実装することは非常に困難であり、継続的なメンテナンスと改善が必要です。
アトム化 (Atomization)
アトム化とは、特定の文字列(この文脈ではHTMLのタグ名や属性名など)を、より効率的な表現、通常は一意の整数値にマッピングするプロセスです。この整数値は「アトム」と呼ばれます。
アトム化の主な利点は以下の通りです。
- パフォーマンスの向上: 文字列の比較は、文字ごとに比較を行うため、計算コストが高くなる可能性があります。一方、アトム化された整数値の比較は、単一のCPU命令で完了することが多く、非常に高速です。HTMLパーシングのように、タグ名や属性名の比較が頻繁に行われる処理では、このパフォーマンス向上が顕著に現れます。
- メモリ使用量の削減: 同じ文字列が何度も出現する場合、その文字列を毎回メモリに格納する代わりに、一度だけ格納し、それ以降はその文字列に対応するアトム(整数値)を使用することで、メモリ使用量を大幅に削減できます。これは、特に大規模なHTMLドキュメントや、多数のHTMLドキュメントを処理する場合に有効です。
exp/html/atom
パッケージは、このアトム化の概念をGo言語で実装していました。HTMLのタグ名(例: "div", "p")や属性名(例: "id", "class")をAtom
型(uint32
のエイリアス)にマッピングし、Lookup
関数を通じて文字列からアトムへの変換、String()
メソッドを通じてアトムから文字列への変換を提供していました。内部的には、ハッシュテーブルと衝突解決のメカニズム(クックーハッシュなど)を用いて、効率的なルックアップを実現していました。
技術的詳細
exp/html
パッケージは、Go言語でHTML5ドキュメントを解析し、操作するための包括的な機能を提供していました。その主要なコンポーネントと機能は以下の通りです。
- HTMLパーサー (
parse.go
): HTML5の複雑なパーシングアルゴリズムを実装していました。これは、ストリーミングパーサーであり、入力ストリームからトークンを読み込み、それらを基にDOMツリー(Node
構造体で表現される)を構築します。エラー回復メカニズムも含まれており、不正なHTMLに対しても堅牢な解析を試みます。 - DOM構造の表現 (
node.go
): 解析されたHTMLドキュメントは、Node
構造体のツリーとしてメモリ上に表現されます。Node
は、要素、テキスト、コメント、DOCTYPEなどのHTMLノードの種類を表現し、親子関係や兄弟関係を持つことができます。 - アトム化 (
atom/atom.go
,atom/table.go
,atom/gen.go
): HTMLのタグ名や属性名など、頻繁に出現する文字列を効率的に扱うためのアトム化メカニズムを提供していました。atom.go
:Atom
型(uint32
のエイリアス)を定義し、文字列からアトムへのLookup
関数、アトムから文字列へのString
メソッドを提供します。内部的には、FNVハッシュ関数とクックーハッシュ(またはそれに類する衝突解決)を用いたハッシュテーブルを使用していました。table.go
:atom.go
で使用されるアトムの定数(例:atom.Div
,atom.A
)と、それらの文字列値、そしてハッシュテーブルのデータが自動生成されていました。gen.go
:table.go
とtable_test.go
を生成するためのGoプログラムです。HTML5の要素名、属性名、イベントハンドラ名などのリストを基に、効率的なアトム化のためのハッシュテーブルと定数を生成します。この生成プロセスでは、文字列の重複を排除し、オーバーラップを利用して文字列データをコンパクトに格納するなどの最適化が行われていました。
- エンティティ処理 (
entity.go
): HTMLエンティティ(例:&
,<
,&
)を処理し、対応するUnicode文字に変換する機能を提供していました。 - レンダリング (
render.go
): 構築されたDOMツリーをHTML文字列として再構築する機能を提供していました。これは、HTMLの整形や、DOM操作後の出力に利用されます。 - テストデータ (
testdata/
): WebKitのテストスイートなど、様々なHTML5パーシングのテストケースが含まれており、パーサーの正確性と堅牢性を検証するために使用されていました。
これらのパッケージがGoのメインリポジトリからgo.net
に移動された理由は、前述の「変更の背景」で述べた通り、Go標準ライブラリの厳格な互換性保証と、HTML5仕様の動的な性質との間のミスマッチを解消するためです。go.net
に移動することで、開発者はAPIの変更をより自由に行えるようになり、HTML5の進化に追従し、より高度な機能を追加するための柔軟性を確保できました。これは、特にブラウザエンジンや高度なHTML処理ツールを構築する際に必要となる、継続的な改善と適応を可能にするための戦略的な判断でした。
コアとなるコードの変更箇所
このコミットは、exp/html
およびexp/html/atom
ディレクトリ配下の全てのファイルを削除するものです。したがって、具体的なコードの変更(追加や修正)はありませんが、削除されたファイル群がこのコミットの「コアとなる変更箇所」と言えます。
特に、以下のファイルはexp/html
パッケージの中核をなすものでした。
src/pkg/exp/html/atom/atom.go
: アトム化の基盤となるAtom
型と、文字列とアトム間の変換ロジックが定義されていました。src/pkg/exp/html/atom/gen.go
: アトム化のための定数とハッシュテーブルを生成するツールであり、アトム化の効率性を担保する重要な役割を担っていました。src/pkg/exp/html/atom/table.go
:gen.go
によって生成される、実際のアトム定数とルックアップテーブルが含まれていました。src/pkg/exp/html/parse.go
: HTML5パーシングの主要なロジックが実装されており、HTMLドキュメントをDOMツリーに変換する役割を担っていました。src/pkg/exp/html/node.go
: HTMLドキュメントのDOMツリー構造を表現するNode
型が定義されていました。src/pkg/exp/html/entity.go
: HTMLエンティティの処理ロジックが含まれていました。
これらのファイルが削除されたことで、GoのメインリポジトリからはHTMLパーシング機能が一時的に失われましたが、これはgo.net/html
への移行準備の一環でした。
コアとなるコードの解説
このコミットで削除されたコードは、Go言語におけるHTML5パーシングとアトム化の初期実装を代表するものでした。以下に、削除された主要なコードの機能と役割を解説します。
src/pkg/exp/html/atom/atom.go
このファイルは、HTMLのタグ名や属性名を効率的に扱うための「アトム化」の概念を実装していました。
type Atom uint32
:Atom
型はuint32
のエイリアスとして定義されており、各HTML文字列(例: "div", "class")を一意の整数値にマッピングします。これにより、文字列比較の代わりに高速な整数比較が可能になります。func (a Atom) String() string
:Atom
型の値を対応する文字列に変換するメソッドです。アトムの内部表現(文字列の開始オフセットと長さ)を利用して、atomText
という巨大な文字列定数から部分文字列を効率的に取得します。func Lookup(s []byte) Atom
: バイトスライスで与えられた文字列s
に対応するAtom
を検索する関数です。この関数は、FNVハッシュ関数(fnv
)と、table
というハッシュテーブルを使用して、高速なルックアップを実現していました。衝突解決のために、2つのハッシュ値を用いてテーブル内の2つの位置をチェックするクックーハッシュのようなアプローチが取られていました。func fnv(h uint32, s []byte) uint32
: FNV (Fowler-Noll-Vo) ハッシュアルゴリズムの実装です。文字列からハッシュ値を計算するために使用されます。
src/pkg/exp/html/atom/gen.go
このファイルは、atom
パッケージで使用される定数とルックアップテーブル(table.go
)を自動生成するためのGoプログラムでした。
identifier(s string) string
: HTML文字列(例: "accept-charset")をGoの識別子(例: "AcceptCharset")に変換するヘルパー関数です。main()
関数:- HTML要素名、属性名、イベントハンドラ名などのリストを結合し、重複を排除します。
- 最適なハッシュテーブルのサイズと初期ハッシュ値(
hash0
)を見つけるために、ランダムな試行を繰り返します。これは、クックーハッシュの特性上、最適なパラメータを見つける必要があるためです。 - 文字列のオーバーラップを利用して、
atomText
という巨大な文字列定数を可能な限りコンパクトに生成します。これにより、メモリ使用量を削減します。 - 最終的に、
Atom
型の定数定義と、table
配列、atomText
定数を含むGoコードを標準出力に出力します。
src/pkg/exp/html/atom/table.go
このファイルは、gen.go
によって自動生成されるGoコードであり、atom
パッケージの核心部分を構成していました。
const (...)
: HTMLの各要素名や属性名に対応するAtom
型の定数が定義されていました。これらの定数には、文字列のatomText
内での開始オフセットと長さがエンコードされていました。const hash0 = ...
: ハッシュ計算の初期値です。const maxAtomLen = ...
: アトム化される文字列の最大長です。var table = [1<<N]Atom{...}
: アトムルックアップのためのハッシュテーブルです。キーはハッシュ値、値は対応するAtom
です。const atomText = ...
: アトム化された全ての文字列が連結された巨大な文字列定数です。Atom
型のString()
メソッドはこの文字列から対応する部分文字列を抽出します。
src/pkg/exp/html/parse.go
このファイルは、HTML5のパーシングアルゴリズムの主要な実装を含んでいました。
type Parser struct { ... }
: HTMLドキュメントを解析するためのパーサーの状態を保持する構造体です。func Parse(r io.Reader) (*Node, error)
:io.Reader
からHTMLを読み込み、解析してDOMツリーのルートノード(*Node
)を返す関数です。- 内部的には、HTML5の複雑なトークナイゼーションとツリー構築のアルゴリズム(挿入モード、スタック、テンプレート挿入モードなど)が実装されていました。エラー回復のためのロジックも含まれており、不正なHTMLに対してもDOMツリーを構築しようとします。
これらのコードは、Go言語でHTMLを効率的かつ正確に処理するための基盤を提供していましたが、Go標準ライブラリの互換性保証の制約から、より柔軟な開発が可能なgo.net
サブモジュールへとその役割を移すことになりました。
関連リンク
- Go CL (Matching Change): https://golang.org/cl/7310063
- Go CL (This Commit): https://golang.org/cl/7317043
- Google Groups Discussion: https://groups.google.com/d/topic/golang-nuts/Qq5hTQyPuLg/discussion
参考にした情報源リンク
- https://groups.google.com/d/topic/golang-nuts/Qq5hTQyPuLg/discussion
- Go言語の
exp
パッケージに関する一般的な情報 - Go言語の外部リポジトリ(
golang.org/x/
)に関する一般的な情報 - HTML5パーシング仕様に関する一般的な情報 (WHATWG HTML Living Standard)
- FNVハッシュアルゴリズムに関する一般的な情報
- クックーハッシュに関する一般的な情報
- Go言語のソースコード(削除された
exp/html
パッケージのコード)I have provided the comprehensive technical explanation in Markdown format, following all the specified instructions and chapter structure. The output is to standard output only, as requested.