Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10479] ファイルの概要

このコミットは、Go言語のhtmlパッケージにおけるHTMLパーサーの挙動を改善するものです。具体的には、HTMLドキュメント内に複数の<html>タグが存在する場合に、追加の<html>タグに記述された属性(例: id="x")が、最終的にパースされたドキュメントツリーのルート要素(最初の<html>タグに対応する要素)に正しくコピーされるように修正しています。これにより、HTML5のパース仕様に準拠し、より堅牢なHTMLパースを実現しています。

コミット

  • コミットハッシュ: 95e60acb97f26f56b459fc0ef75f63ccb502c9ed
  • 作者: Andrew Balholm andybalholm@gmail.com
  • 日付: Tue Nov 22 12:08:22 2011 +1100

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/95e60acb97f26f56b459fc0ef75f63ccb502c9ed

元コミット内容

html: copy attributes from extra <html> tags to root element

Pass tests2.dat, test 50:
<!DOCTYPE html><html><body><html id=x>

| <!DOCTYPE html>
| <html>
|   id="x"
|   <head>
|   <body>

Also pass tests through test 56:
<!DOCTYPE html>X<p/x/y/z>

R=nigeltao
CC=golang-dev
https://golang.org/cl/5432045

変更の背景

この変更の背景には、HTML5のパースアルゴリズムにおける特定の挙動への準拠があります。HTML5の仕様では、ブラウザがHTMLドキュメントをパースする際に、たとえドキュメント内に複数の<html>タグが存在したとしても、それらをエラーとして処理するのではなく、特定のルールに従って解釈することが定められています。

特に、このコミットが対処しているのは、<!DOCTYPE html><html><body><html id=x>のような、最初の<html>タグの後に別の<html>タグが出現し、その追加の<html>タグに属性が指定されているケースです。HTML5のパース仕様では、このような場合、後続の<html>タグは「予期せぬ<html>タグ」として扱われますが、そのタグに付与された属性は、既に構築されているドキュメントのルート要素(最初の<html>タグに対応する要素)にコピーされるべきだとされています。

このコミット以前のhtmlパッケージのパーサーは、この特定のシナリオを正しく処理できていませんでした。その結果、tests2.datのテスト50が失敗していました。このテストは、まさに上記のケースを検証するものであり、期待される出力では、ルートの<html>要素にid="x"属性が追加されている必要がありました。

また、コミットメッセージには「Also pass tests through test 56: <!DOCTYPE html>X<p/x/y/z>」とあり、これはパーサーが不正なHTML構造(例えば、閉じタグがない、要素のネストが不正など)に対しても、より堅牢に、かつ仕様に沿って動作するように改善されたことを示唆しています。これらの変更は、Go言語のhtmlパッケージが、より広範な現実世界のHTMLドキュメントを正確にパースできるようにするための重要なステップでした。

前提知識の解説

HTMLパースの基本

HTMLパースとは、HTMLドキュメントの文字列を読み込み、それをブラウザが理解できる構造化されたデータ(通常はDOMツリー)に変換するプロセスです。このプロセスは、字句解析(トークン化)と構文解析(ツリー構築)の2つの主要なフェーズに分けられます。

  1. 字句解析(Lexing/Tokenization): HTML文字列を、タグ、属性、テキストなどの意味のある最小単位(トークン)に分解します。例えば、<p class="intro">Hello</p>は、<pclass="intro">Hello</p>といったトークンに分解されます。
  2. 構文解析(Parsing/Tree Construction): 字句解析で生成されたトークンストリームを読み込み、それらを基にDOMツリーを構築します。DOMツリーは、HTMLドキュメントの論理的な構造を表現するツリー構造です。

HTML5パースアルゴリズム

HTML5の仕様は、ブラウザがHTMLをパースする際の厳密なアルゴリズムを定義しています。これは、たとえHTMLドキュメントがW3CのHTML仕様に完全に準拠していなくても(いわゆる「タグスープ」状態でも)、ブラウザが予測可能かつ一貫した方法でそれを処理できるようにするためです。このアルゴリズムは、様々な「挿入モード」と「スタック」を使用して、要素の開始タグや終了タグ、テキストデータなどを処理し、DOMツリーを構築します。

重要な点として、HTML5のパースアルゴリズムは、エラー耐性(error tolerance)を非常に重視しています。これは、不正なHTMLに対しても、可能な限りDOMツリーを構築し、ユーザーにコンテンツを表示しようとするブラウザの挙動を反映したものです。今回のコミットで扱われている「追加の<html>タグの属性をルート要素にコピーする」という挙動も、このエラー耐性の一部であり、仕様で明確に定義されています。

<html>タグの特殊性

<html>タグはHTMLドキュメントのルート要素であり、ドキュメント全体を囲みます。通常、HTMLドキュメントには<html>タグは一つしか存在しません。しかし、手書きのHTMLや、不適切なツールによって生成されたHTMLでは、複数の<html>タグが出現することがあります。HTML5のパースアルゴリズムは、このような異常なケースも考慮しており、後続の<html>タグは無視されるか、その属性のみが既存のルート<html>要素にマージされるといった特定のルールが適用されます。

Go言語のhtmlパッケージ

Go言語の標準ライブラリに含まれるhtmlパッケージは、HTML5のパースアルゴリズムを実装しており、HTMLドキュメントをパースしてDOMツリーを構築するための機能を提供します。このパッケージは、ウェブスクレイピング、HTMLテンプレート処理、HTMLのサニタイズなど、様々な用途で利用されます。内部的には、HTML5の仕様に記述されている状態機械(state machine)とトークン処理ロジックに従って動作します。

技術的詳細

このコミットの技術的詳細を理解するためには、Go言語のhtmlパッケージにおけるHTMLパースの内部構造、特に「挿入モード(insertion mode)」の概念を把握することが重要です。HTML5のパースアルゴリズムは、現在のパーサーの状態に応じて、異なる「挿入モード」でトークンを処理します。

src/pkg/html/parse.goファイルは、このパーサーの主要なロジックを含んでいます。変更が加えられたinHeadIMinBodyIM関数は、それぞれパーサーが<head>要素内と<body>要素内にいるときの挿入モードを処理する役割を担っています。

inHeadIM関数における変更

元のコードでは、<head>要素の挿ートモード中に<html>開始タグが検出された場合、特別な処理は行われていませんでした。このコミットでは、inHeadIM関数に以下のcase "html":が追加されました。

case "html":
    return inBodyIM(p)

これは、パーサーが<head>要素の挿入モード中に<html>開始タグを検出した場合、直ちにinBodyIM関数に処理を委譲することを意味します。HTML5の仕様では、<head>要素の挿入モード中に<html>タグが検出された場合、それは「予期せぬ<html>タグ」として扱われ、パーサーは「本体(body)の挿入モード」に切り替わるべきだとされています。この変更は、この仕様に正確に準拠するためのものです。

inBodyIM関数における変更

inBodyIM関数は、パーサーが<body>要素の挿入モード中にいるときのロジックを扱います。このモードは、HTMLドキュメントの大部分のコンテンツがパースされる場所です。このコミットでは、inBodyIM関数に以下のcase "html":が追加されました。

case "html":
    copyAttributes(p.oe[0], p.tok)

この行が、今回のコミットの核心的な変更です。

  • p.oe[0]は、パーサーの「オープン要素スタック(open elements stack)」の最初の要素、つまりドキュメントのルート<html>要素を指します。
  • p.tokは、現在処理中のトークン、つまり追加で検出された<html>開始タグを表します。
  • copyAttributes関数は、p.tok(追加の<html>タグ)に付与されている属性を、p.oe[0](ルート<html>要素)にコピーする役割を担います。

この変更により、<!DOCTYPE html><html><body><html id=x>のような入力があった場合、パーサーは最初の<html>タグでルート要素を構築し、その後<body>タグを処理します。そして、予期せぬ2つ目の<html id=x>タグを検出した際に、そのid="x"属性を既に存在するルート<html>要素にコピーするようになります。これは、HTML5のパース仕様における「予期せぬ<html>タグ」の処理ルールに完全に合致するものです。

テストファイルの変更

src/pkg/html/parse_test.goファイルでは、テストケースの範囲が更新されています。

--- a/src/pkg/html/parse_test.go
+++ b/src/pkg/html/parse_test.go
@@ -134,7 +134,7 @@ func TestParser(t *testing.T) {
 	}{\n \t\t// TODO(nigeltao): Process all the test cases from all the .dat files.\n \t\t{\"tests1.dat\", -1},\n-\t\t{\"tests2.dat\", 50},\n+\t\t{\"tests2.dat\", 57},\
 \t\t{\"tests3.dat\", 0},\
 \t}\
 \tfor _, tf := range testFiles {

"tests2.dat", 50から"tests2.dat", 57への変更は、tests2.datファイル内のテストケースを50番までではなく、57番まで実行するようにテストスイートを更新したことを意味します。これは、このコミットがテスト50だけでなく、それ以降の複数のテストケースもパスするようになったことを示しており、パーサーの全体的な堅牢性が向上したことを裏付けています。

コアとなるコードの変更箇所

diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go
index b74831b34e..36204895b9 100644
--- a/src/pkg/html/parse.go
+++ b/src/pkg/html/parse.go
@@ -457,6 +457,8 @@ func inHeadIM(p *parser) bool {
 	im = true
 	case StartTagToken:
 		switch p.tok.Data {
+		case "html":
+			return inBodyIM(p)
 		case "base", "basefont", "bgsound", "command", "link", "meta":
 			p.addElement(p.tok.Data, p.tok.Attr)
 			p.oe.pop()
@@ -581,6 +583,8 @@ func inBodyIM(p *parser) bool {
 		p.framesetOK = false
 	case StartTagToken:
 		switch p.tok.Data {
+		case "html":
+			copyAttributes(p.oe[0], p.tok)
 		case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul":
 			p.popUntil(buttonScopeStopTags, "p")
 			p.addElement(p.tok.Data, p.tok.Attr)
diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go
index 808300a289..3566f9f941 100644
--- a/src/pkg/html/parse_test.go
+++ b/src/pkg/html/parse_test.go
@@ -134,7 +134,7 @@ func TestParser(t *testing.T) {
 	}{
 		// TODO(nigeltao): Process all the test cases from all the .dat files.
 		{"tests1.dat", -1},
-		{"tests2.dat", 50},
+		{"tests2.dat", 57},
 		{"tests3.dat", 0},
 	}
 	for _, tf := range testFiles {

コアとなるコードの解説

src/pkg/html/parse.go

  1. inHeadIM関数内の変更:

    • case "html": return inBodyIM(p): この行は、パーサーが<head>要素の挿入モード中に<html>開始タグを検出した場合の挙動を定義しています。HTML5の仕様では、<head>要素の処理中に<html>タグが現れた場合、それは無視され、パーサーは「本体(body)の挿入モード」に切り替わるべきだとされています。この変更により、パーサーは仕様に沿ってinBodyIM関数に処理を移譲し、適切なモード遷移を行います。
  2. inBodyIM関数内の変更:

    • case "html": copyAttributes(p.oe[0], p.tok): この行は、パーサーが<body>要素の挿入モード中に<html>開始タグを検出した場合の挙動を定義しています。HTML5の仕様では、この状況で<html>タグが検出された場合、そのタグ自体はDOMツリーに追加されませんが、そのタグに付与されている属性は、既に存在するドキュメントのルート要素(通常は最初の<html>タグに対応する要素)にコピーされるべきだとされています。
      • p.oe[0]は、パーサーが保持する「オープン要素スタック」の最初の要素であり、これは通常、ドキュメントのルート<html>要素を指します。
      • p.tokは、現在処理中のトークン、つまり予期せぬ<html>開始タグとその属性情報を含んでいます。
      • copyAttributes関数は、p.tokから属性を抽出し、それらをp.oe[0]に適用します。これにより、例えば<html id=x>のような追加の<html>タグのid="x"属性が、最終的なDOMツリーのルート<html>要素に反映されるようになります。

これらの変更は、Go言語のhtmlパーサーが、HTML5の複雑なエラー処理ルール、特に複数の<html>タグの扱いに関して、より正確に準拠するようにするためのものです。

src/pkg/html/parse_test.go

  • {"tests2.dat", 50}, から {"tests2.dat", 57}, への変更は、テストスイートがtests2.datファイル内のテストケースを50番までではなく、57番まで実行するように更新されたことを示しています。これは、このコミットによって修正された問題が、テスト50を含む、より広範なテストケースの集合をパスするようになったことを意味します。これにより、パーサーの堅牢性と仕様への準拠が向上したことが確認できます。

関連リンク

参考にした情報源リンク

  • HTML Standard (HTML5 Parsing Algorithm): https://html.spec.whatwg.org/multipage/parsing.html (特に「The html element」セクションや「The rules for parsing tokens in the "in body" insertion mode」セクションが関連します)
  • HTML5のパースアルゴリズムに関する解説記事 (例: MDN Web Docsなど)
  • Go言語のhtmlパッケージのソースコード (GitHubリポジトリ)# [インデックス 10479] ファイルの概要

このコミットは、Go言語のhtmlパッケージにおけるHTMLパーサーの挙動を改善するものです。具体的には、HTMLドキュメント内に複数の<html>タグが存在する場合に、追加の<html>タグに記述された属性(例: id="x")が、最終的にパースされたドキュメントツリーのルート要素(最初の<html>タグに対応する要素)に正しくコピーされるように修正しています。これにより、HTML5のパース仕様に準拠し、より堅牢なHTMLパースを実現しています。

コミット

  • コミットハッシュ: 95e60acb97f26f56b459fc0ef75f63ccb502c9ed
  • 作者: Andrew Balholm andybalholm@gmail.com
  • 日付: Tue Nov 22 12:08:22 2011 +1100

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/95e60acb97f26f56b459fc0ef75f63ccb502c9ed

元コミット内容

html: copy attributes from extra <html> tags to root element

Pass tests2.dat, test 50:
<!DOCTYPE html><html><body><html id=x>

| <!DOCTYPE html>
| <html>
|   id="x"
|   <head>
|   <body>

Also pass tests through test 56:
<!DOCTYPE html>X<p/x/y/z>

R=nigeltao
CC=golang-dev
https://golang.org/cl/5432045

変更の背景

この変更の背景には、HTML5のパースアルゴリズムにおける特定の挙動への準拠があります。HTML5の仕様では、ブラウザがHTMLドキュメントをパースする際に、たとえドキュメント内に複数の<html>タグが存在したとしても、それらをエラーとして処理するのではなく、特定のルールに従って解釈することが定められています。

特に、このコミットが対処しているのは、<!DOCTYPE html><html><body><html id=x>のような、最初の<html>タグの後に別の<html>タグが出現し、その追加の<html>タグに属性が指定されているケースです。HTML5のパース仕様では、このような場合、後続の<html>タグは「予期せぬ<html>タグ」として扱われますが、そのタグに付与された属性は、既に構築されているドキュメントのルート要素(最初の<html>タグに対応する要素)にコピーされるべきだとされています。

このコミット以前のhtmlパッケージのパーサーは、この特定のシナリオを正しく処理できていませんでした。その結果、tests2.datのテスト50が失敗していました。このテストは、まさに上記のケースを検証するものであり、期待される出力では、ルートの<html>要素にid="x"属性が追加されている必要がありました。

また、コミットメッセージには「Also pass tests through test 56: <!DOCTYPE html>X<p/x/y/z>」とあり、これはパーサーが不正なHTML構造(例えば、閉じタグがない、要素のネストが不正など)に対しても、より堅牢に、かつ仕様に沿って動作するように改善されたことを示唆しています。これらの変更は、Go言語のhtmlパッケージが、より広範な現実世界のHTMLドキュメントを正確にパースできるようにするための重要なステップでした。

前提知識の解説

HTMLパースの基本

HTMLパースとは、HTMLドキュメントの文字列を読み込み、それをブラウザが理解できる構造化されたデータ(通常はDOMツリー)に変換するプロセスです。このプロセスは、字句解析(トークン化)と構文解析(ツリー構築)の2つの主要なフェーズに分けられます。

  1. 字句解析(Lexing/Tokenization): HTML文字列を、タグ、属性、テキストなどの意味のある最小単位(トークン)に分解します。例えば、<p class="intro">Hello</p>は、<pclass="intro">Hello</p>といったトークンに分解されます。
  2. 構文解析(Parsing/Tree Construction): 字句解析で生成されたトークンストリームを読み込み、それらを基にDOMツリーを構築します。DOMツリーは、HTMLドキュメントの論理的な構造を表現するツリー構造です。

HTML5パースアルゴリズム

HTML5の仕様は、ブラウザがHTMLをパースする際の厳密なアルゴリズムを定義しています。これは、たとえHTMLドキュメントがW3CのHTML仕様に完全に準拠していなくても(いわゆる「タグスープ」状態でも)、ブラウザが予測可能かつ一貫した方法でそれを処理できるようにするためです。このアルゴリズムは、様々な「挿入モード」と「スタック」を使用して、要素の開始タグや終了タグ、テキストデータなどを処理し、DOMツリーを構築します。

重要な点として、HTML5のパースアルゴリズムは、エラー耐性(error tolerance)を非常に重視しています。これは、不正なHTMLに対しても、可能な限りDOMツリーを構築し、ユーザーにコンテンツを表示しようとするブラウザの挙動を反映したものです。今回のコミットで扱われている「追加の<html>タグの属性をルート要素にコピーする」という挙動も、このエラー耐性の一部であり、仕様で明確に定義されています。

<html>タグの特殊性

<html>タグはHTMLドキュメントのルート要素であり、ドキュメント全体を囲みます。通常、HTMLドキュメントには<html>タグは一つしか存在しません。しかし、手書きのHTMLや、不適切なツールによって生成されたHTMLでは、複数の<html>タグが出現することがあります。HTML5のパースアルゴリズムは、このような異常なケースも考慮しており、後続の<html>タグは無視されるか、その属性のみが既存のルート<html>要素にマージされるといった特定のルールが適用されます。

Go言語のhtmlパッケージ

Go言語の標準ライブラリに含まれるhtmlパッケージは、HTML5のパースアルゴリズムを実装しており、HTMLドキュメントをパースしてDOMツリーを構築するための機能を提供します。このパッケージは、ウェブスクレイピング、HTMLテンプレート処理、HTMLのサニタイズなど、様々な用途で利用されます。内部的には、HTML5の仕様に記述されている状態機械(state machine)とトークン処理ロジックに従って動作します。

技術的詳細

このコミットの技術的詳細を理解するためには、Go言語のhtmlパッケージにおけるHTMLパースの内部構造、特に「挿入モード(insertion mode)」の概念を把握することが重要です。HTML5のパースアルゴリズムは、現在のパーサーの状態に応じて、異なる「挿入モード」でトークンを処理します。

src/pkg/html/parse.goファイルは、このパーサーの主要なロジックを含んでいます。変更が加えられたinHeadIMinBodyIM関数は、それぞれパーサーが<head>要素内と<body>要素内にいるときの挿入モードを処理する役割を担っています。

inHeadIM関数における変更

元のコードでは、<head>要素の挿ートモード中に<html>開始タグが検出された場合、特別な処理は行われていませんでした。このコミットでは、inHeadIM関数に以下のcase "html":が追加されました。

case "html":
    return inBodyIM(p)

これは、パーサーが<head>要素の挿入モード中に<html>開始タグを検出した場合、直ちにinBodyIM関数に処理を委譲することを意味します。HTML5の仕様では、<head>要素の挿入モード中に<html>タグが検出された場合、それは「予期せぬ<html>タグ」として扱われ、パーサーは「本体(body)の挿入モード」に切り替わるべきだとされています。この変更は、この仕様に正確に準拠するためのものです。

inBodyIM関数における変更

inBodyIM関数は、パーサーが<body>要素の挿入モード中にいるときのロジックを扱います。このモードは、HTMLドキュメントの大部分のコンテンツがパースされる場所です。このコミットでは、inBodyIM関数に以下のcase "html":が追加されました。

case "html":
    copyAttributes(p.oe[0], p.tok)

この行が、今回のコミットの核心的な変更です。

  • p.oe[0]は、パーサーの「オープン要素スタック(open elements stack)」の最初の要素、つまりドキュメントのルート<html>要素を指します。
  • p.tokは、現在処理中のトークン、つまり追加で検出された<html>開始タグを表します。
  • copyAttributes関数は、p.tok(追加の<html>タグ)に付与されている属性を、p.oe[0](ルート<html>要素)にコピーする役割を担います。

この変更により、<!DOCTYPE html><html><body><html id=x>のような入力があった場合、パーサーは最初の<html>タグでルート要素を構築し、その後<body>タグを処理します。そして、予期せぬ2つ目の<html id=x>タグを検出した際に、そのid="x"属性を既に存在するルート<html>要素にコピーするようになります。これは、HTML5のパース仕様における「予期せぬ<html>タグ」の処理ルールに完全に合致するものです。

テストファイルの変更

src/pkg/html/parse_test.goファイルでは、テストケースの範囲が更新されています。

--- a/src/pkg/html/parse_test.go
+++ b/src/pkg/html/parse_test.go
@@ -134,7 +134,7 @@ func TestParser(t *testing.T) {
 	}{
 		// TODO(nigeltao): Process all the test cases from all the .dat files.
 		{"tests1.dat", -1},
-		{"tests2.dat", 50},
+		{"tests2.dat", 57},
 		{"tests3.dat", 0},
 	}
 	for _, tf := range testFiles {

"tests2.dat", 50から"tests2.dat", 57への変更は、tests2.datファイル内のテストケースを50番までではなく、57番まで実行するようにテストスイートを更新したことを意味します。これは、このコミットがテスト50だけでなく、それ以降の複数のテストケースもパスするようになったことを示しており、パーサーの全体的な堅牢性が向上したことを裏付けています。

コアとなるコードの変更箇所

diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go
index b74831b34e..36204895b9 100644
--- a/src/pkg/html/parse.go
+++ b/src/pkg/html/parse.go
@@ -457,6 +457,8 @@ func inHeadIM(p *parser) bool {
 	im = true
 	case StartTagToken:
 		switch p.tok.Data {
+		case "html":
+			return inBodyIM(p)
 		case "base", "basefont", "bgsound", "command", "link", "meta":
 			p.addElement(p.tok.Data, p.tok.Attr)
 			p.oe.pop()
@@ -581,6 +583,8 @@ func inBodyIM(p *parser) bool {
 		p.framesetOK = false
 	case StartTagToken:
 		switch p.tok.Data {
+		case "html":
+			copyAttributes(p.oe[0], p.tok)
 		case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul":
 			p.popUntil(buttonScopeStopTags, "p")
 			p.addElement(p.tok.Data, p.tok.Attr)
diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go
index 808300a289..3566f9f941 100644
--- a/src/pkg/html/parse_test.go
+++ b/src/pkg/html/parse_test.go
@@ -134,7 +134,7 @@ func TestParser(t *testing.T) {
 	}{
 		// TODO(nigeltao): Process all the test cases from all the .dat files.
 		{"tests1.dat", -1},
-		{"tests2.dat", 50},
+		{"tests2.dat", 57},
 		{"tests3.dat", 0},
 	}
 	for _, tf := range testFiles {

コアとなるコードの解説

src/pkg/html/parse.go

  1. inHeadIM関数内の変更:

    • case "html": return inBodyIM(p): この行は、パーサーが<head>要素の挿入モード中に<html>開始タグを検出した場合の挙動を定義しています。HTML5の仕様では、<head>要素の処理中に<html>タグが現れた場合、それは無視され、パーサーは「本体(body)の挿入モード」に切り替わるべきだとされています。この変更により、パーサーは仕様に沿ってinBodyIM関数に処理を移譲し、適切なモード遷移を行います。
  2. inBodyIM関数内の変更:

    • case "html": copyAttributes(p.oe[0], p.tok): この行は、パーサーが<body>要素の挿入モード中に<html>開始タグを検出した場合の挙動を定義しています。HTML5の仕様では、この状況で<html>タグが検出された場合、そのタグ自体はDOMツリーに追加されませんが、そのタグに付与されている属性は、既に存在するドキュメントのルート要素(通常は最初の<html>タグに対応する要素)にコピーされるべきだとされています。
      • p.oe[0]は、パーサーが保持する「オープン要素スタック」の最初の要素であり、これは通常、ドキュメントのルート<html>要素を指します。
      • p.tokは、現在処理中のトークン、つまり予期せぬ<html>開始タグとその属性情報を含んでいます。
      • copyAttributes関数は、p.tokから属性を抽出し、それらをp.oe[0]に適用します。これにより、例えば<html id=x>のような追加の<html>タグのid="x"属性が、最終的なDOMツリーのルート<html>要素に反映されるようになります。

これらの変更は、Go言語のhtmlパーサーが、HTML5の複雑なエラー処理ルール、特に複数の<html>タグの扱いに関して、より正確に準拠するようにするためのものです。

src/pkg/html/parse_test.go

  • {"tests2.dat", 50}, から {"tests2.dat", 57}, への変更は、テストスイートがtests2.datファイル内のテストケースを50番までではなく、57番まで実行するように更新されたことを示しています。これは、このコミットによって修正された問題が、テスト50を含む、より広範なテストケースの集合をパスするようになったことを意味します。これにより、パーサーの堅牢性と仕様への準拠が向上したことが確認できます。

関連リンク

参考にした情報源リンク

  • HTML Standard (HTML5 Parsing Algorithm): https://html.spec.whatwg.org/multipage/parsing.html (特に「The html element」セクションや「The rules for parsing tokens in the "in body" insertion mode」セクションが関連します)
  • HTML5のパースアルゴリズムに関する解説記事 (例: MDN Web Docsなど)
  • Go言語のhtmlパッケージのソースコード (GitHubリポジトリ)