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

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

コミット

コミットハッシュ: 3bd5082f579d3a45cfa3969d799bef2539c988f0
作成者: Andrew Balholm andybalholm@gmail.com
作成日: 2011年11月15日(火)11:39:18 +1100
コミットメッセージ: html: parse and render <plaintext> elements

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

https://github.com/golang/go/commit/3bd5082f579d3a45cfa3969d799bef2539c988f0

元コミット内容

このコミットは、GoのHTMLパッケージに<plaintext>要素のパースとレンダリング機能を追加したものです。コミットメッセージには、このコミットがtests2.datのテスト10をパスするようになったことと、テスト25まで通過することが記載されています。

具体的には、以下のテストケースが通過するようになりました:

  • \<table\>\<plaintext\>\<td\> のパースが正しく行われ、DOM構造が適切に構築される
  • \<!doctypehtml\>\<p\>\<dd\> のような複合テストケースも通過

変更の背景

このコミットは2011年のGoの初期開発時期に作成されたものです。当時GoのHTMLパッケージはHTML5仕様に対応した完全なHTMLパーサーとして開発されており、Web標準に準拠したHTMLの解析とレンダリングを目標としていました。

<plaintext>要素は、HTML仕様の中でも特殊な扱いを受ける要素の一つで、HTML5では廃止予定(obsolete)とされていますが、既存のWebコンテンツとの互換性を保つために実装する必要がありました。

このコミットの目的は以下の通りです:

  1. HTML5仕様に準拠したHTMLパーサーとしての完全性を高める
  2. 既存のWebコンテンツとの互換性を確保する
  3. 公式のHTML5テストスイートに対応する

前提知識の解説

<plaintext>要素の特殊性

<plaintext>要素は、HTML仕様の中でも極めて特殊な動作をする要素です:

  1. 終了タグなし: <plaintext>要素は終了タグを持ちません。開始タグの後は全てプレーンテキストとして扱われます。

  2. パーサーの停止: <plaintext>要素に遭遇すると、HTMLパーサーは後続の内容を全てテキストとして扱い、HTMLタグとして解析しません。

  3. 廃止予定: HTML5では<plaintext>要素は廃止予定(obsolete)とされており、代わりに<pre>要素や<code>要素の使用が推奨されています。

  4. 歴史的経緯: <plaintext>要素は初期のHTMLで、文書の残りの部分を生テキストとして表示するために使用されていました。

HTMLパーサーの動作原理

HTMLパーサーは以下の段階で動作します:

  1. トークナイザー(Tokenizer): HTML文字列を意味のあるトークンに分割
  2. パーサー(Parser): トークンからDOMツリーを構築
  3. レンダラー(Renderer): DOMツリーをHTML文字列に変換

<plaintext>要素は、これらの各段階で特殊な処理が必要となります。

Go言語のHTMLパッケージ

2011年当時のGoのHTMLパッケージは、以下の特徴を持っていました:

  • HTML5仕様に準拠した実装
  • トークナイザーとパーサーの分離設計
  • 低レベルAPIと高レベルAPIの両方を提供
  • 厳密な仕様準拠を目指した実装

技術的詳細

実装された機能

このコミットでは、以下の4つのファイルが変更されました:

  1. parse.go: <plaintext>要素のパース処理を追加
  2. parse_test.go: テストケースの更新とブラックリストの追加
  3. render.go: <plaintext>要素のレンダリング処理を追加
  4. token.go: トークナイザーに<plaintext>要素の特殊処理を追加

パーサーの状態管理

HTMLパーサーは状態機械として実装されており、<plaintext>要素に遭遇すると特殊な状態に遷移します:

  • 通常状態: HTMLタグを解析してDOMツリーを構築
  • PLAINTEXT状態: 後続の全ての内容をテキストとして扱う

レンダリングの特殊処理

<plaintext>要素のレンダリングでは、以下の特殊処理が実装されています:

  1. 内容の生出力: 子要素の内容を生のテキストとして出力
  2. 終了タグの省略: <plaintext>要素の終了タグは出力しない
  3. レンダリング停止: <plaintext>要素の後は何も出力しない

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

1. parse.go:655-660行目

case "plaintext":
    p.popUntil(buttonScopeStopTags, "p")
    p.addElement(p.tok.Data, p.tok.Attr)

この変更により、<plaintext>要素に遭遇した際の処理が追加されました。

2. render.go:73-84行目

// plaintextAbort is returned from render1 when a <plaintext> element 
// has been rendered. No more end tags should be rendered after that.
var plaintextAbort = errors.New("html: internal error (plaintext abort)")

func render(w writer, n *Node) error {
    err := render1(w, n)
    if err == plaintextAbort {
        err = nil
    }
    return err
}

レンダリング停止のための特殊エラーハンドリングが追加されました。

3. token.go:161-170行目

if z.rawTag == "plaintext" {
    // Read everything up to EOF.
    for z.err == nil {
        z.readByte()
    }
    z.textIsRaw = true
} else {
    z.readRawOrRCDATA()
}

トークナイザーに<plaintext>要素の特殊処理が追加されました。

コアとなるコードの解説

パーサーの実装

parse.goの変更では、inBodyIM関数内で<plaintext>要素の処理が追加されています:

case "plaintext":
    p.popUntil(buttonScopeStopTags, "p")
    p.addElement(p.tok.Data, p.tok.Attr)

この処理では:

  1. popUntilでボタンスコープまでの<p>要素をポップ
  2. addElementで<plaintext>要素をDOMに追加

これにより、<plaintext>要素が適切にDOMツリーに組み込まれます。

レンダラーの実装

render.goの変更では、<plaintext>要素専用の停止機構が実装されています:

if n.Data == "plaintext" {
    // Don't render anything else. <plaintext> must be the
    // last element in the file, with no closing tag.
    return plaintextAbort
}

この実装により、<plaintext>要素の後は何もレンダリングされなくなります。

トークナイザーの実装

token.goの変更では、<plaintext>要素の特殊なトークン化処理が実装されています:

if z.rawTag == "plaintext" {
    // Read everything up to EOF.
    for z.err == nil {
        z.readByte()
    }
    z.textIsRaw = true
}

この処理により、<plaintext>要素以降の全ての内容がテキストとして扱われます。

テストケースの更新

parse_test.goでは、テストケースの範囲が拡張され、<plaintext>要素のテストが追加されています:

{"tests2.dat", 26}, // 10から26に変更

また、レンダリングのブラックリストに<plaintext>要素のテストケースが追加されています:

// A <plaintext> element is reparented, putting it before a table.
// A <plaintext> element can't have anything after it in HTML.
`<table><plaintext><td>`: true,

関連リンク

参考にした情報源リンク

  1. HTML Standard - Obsolete features
  2. HTML Standard - Parsing HTML documents
  3. MDN Web Docs - <plaintext>: The Plain Text element (Deprecated)
  4. Go Packages - html package
  5. HTML5 Specification - Tokenization
  6. W3C HTML5 - Obsolete elements