[インデックス 12154] ファイルの概要
このコミットは、Go言語の標準ライブラリ encoding/xml
パッケージに関連する変更を含んでいます。具体的には、以下の2つのファイルが変更されています。
src/pkg/encoding/xml/example_test.go
:encoding/xml
パッケージの利用例を記述したテストファイルです。このファイルでは、xml.Unmarshal
の新しい例が追加され、既存のxml.MarshalIndent
の例が修正されています。src/pkg/encoding/xml/read.go
:encoding/xml
パッケージの内部実装ファイルで、XMLの読み込み(アンマーシャリング)に関連するロジックが含まれています。このコミットでは、Unmarshal
関数のドキュメントコメントから、以前のUnmarshal
の使用例が削除されています。
コミット
- コミットハッシュ:
133c6bf77fffcbfa38ed58cf06808b38bbc374e0
- Author: Gustavo Niemeyer gustavo@niemeyer.net
- Date: Wed Feb 22 23:37:57 2012 -0200
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/133c6bf77fffcbfa38ed58cf06808b38bbc374e0
元コミット内容
encoding/xml: move Unmarshal example to function
This also fixes MarshalIndent's example after the
recent formatting convention changes.
Fixes #2831.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5671062
変更の背景
このコミットは、主に encoding/xml
パッケージの Unmarshal
関数の使用例を、ドキュメントコメントから独立したテスト関数 (ExampleUnmarshal
) へと移動させることを目的としています。これにより、Goの標準的な例の記述方法に準拠し、go test
コマンドで例が実行・検証されるようになります。
また、MarshalIndent
関数の例も修正されています。これは、最近のGoのコードフォーマット規約の変更(おそらくインデントに関するもの)に対応するためです。コミットメッセージにある Fixes #2831
は、この変更が特定の課題(Issue 2831)を解決することを示唆していますが、現在のGitHubリポジトリでは直接的なIssue 2831は見つかりませんでした。しかし、GoのIssueトラッカーは時期によって異なる場合があるため、当時のGoのIssueトラッカーで追跡されていた問題である可能性が高いです。
前提知識の解説
Go言語の encoding/xml
パッケージ
encoding/xml
パッケージは、GoプログラムとXMLデータの間で構造体とXML要素を相互に変換(マーシャリングとアンマーシャリング)するための機能を提供します。
- マーシャリング (Marshaling): Goの構造体のデータをXML形式に変換すること。
xml.Marshal
やxml.MarshalIndent
関数がこれにあたります。xml.MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
: 構造体v
をXMLバイト列に変換します。prefix
は各行の先頭に付加される文字列、indent
はインデントに使用される文字列です。これにより、整形された(インデントされた)XMLが出力されます。
- アンマーシャリング (Unmarshaling): XMLデータをGoの構造体に変換すること。
xml.Unmarshal
関数がこれにあたります。xml.Unmarshal(data []byte, v interface{}) error
: XMLバイト列data
をGoの構造体v
に変換します。
Go言語の Example
関数
Go言語では、パッケージの使用例を Example
関数として記述する慣習があります。これらの関数は _test.go
ファイル内に記述され、go test
コマンドを実行する際に自動的にテストされ、ドキュメント生成ツール (go doc
) によってドキュメントに組み込まれます。
Example
関数の特徴は以下の通りです。
- 関数名のプレフィックスが
Example
であること(例:ExampleUnmarshal
)。 - 関数内に
// Output:
コメントブロックを含めることで、その例の標準出力が期待される出力と一致するかどうかがgo test
によって検証されること。これにより、例が常に正しく動作することが保証されます。
XMLの構造とGo構造体へのマッピング
encoding/xml
パッケージでは、Goの構造体のフィールドにタグ (xml:"elementName"
, xml:"attrName,attr"
) を付与することで、XML要素や属性とのマッピングを制御します。
xml:"elementName"
: フィールドが対応するXML要素の名前を指定します。xml:"attrName,attr"
: フィールドが対応するXML属性の名前を指定します。xml:"-"
: フィールドをXMLに含めないことを示します。xml:",innerxml"
: フィールドが要素の内部XMLコンテンツを保持することを示します。xml:"parent>child"
: ネストされた要素のパスを指定します。
技術的詳細
このコミットの主要な変更点は、encoding/xml
パッケージの Unmarshal
関数の使用例を、src/pkg/encoding/xml/read.go
のドキュメントコメントから src/pkg/encoding/xml/example_test.go
内の ExampleUnmarshal
関数へと移動させたことです。
Unmarshal
例の移動
以前は read.go
内の Unmarshal
関数のドキュメントコメントに、XMLデータとそれに対応するGo構造体の定義、そしてアンマーシャリング後の結果が詳細に記述されていました。これはドキュメントとしては有用でしたが、Goの Example
関数の慣習に沿っていませんでした。
このコミットにより、この例は example_test.go
に完全に移植され、ExampleUnmarshal
という独立した関数になりました。これにより、以下の利点が得られます。
- 自動テストと検証:
go test
コマンドを実行するたびに、この例が実際に動作し、期待される出力 (// Output:
コメントで指定されたもの) と一致することが検証されます。これにより、例が古くなったり、バグを含んだりするリスクが低減します。 - ドキュメントの改善:
go doc
コマンドでencoding/xml
パッケージのドキュメントを生成する際に、この例が自動的に組み込まれ、よりインタラクティブで信頼性の高いドキュメントが提供されます。 - コードとドキュメントの一貫性: コードベース内の例の記述方法が統一され、Goの標準的なプラクティスに準拠します。
MarshalIndent
例の修正
example_test.go
内の既存の ExampleMarshalIndent
関数も修正されています。以前はインデントにタブ (\t
) を使用していましたが、このコミットではスペース (
と
) に変更されています。これは、コミットメッセージにある「最近のフォーマット規約の変更」に対応するためです。Goコミュニティでは、コードの可読性と一貫性を保つために、インデントにタブではなくスペースを使用する慣習が広まっていました(特に gofmt
ツールによって強制される)。この変更は、その規約に合わせたものです。
コアとなるコードの変更箇所
src/pkg/encoding/xml/example_test.go
- 追加:
ExampleUnmarshal
関数が新規に追加されました。この関数は、Email
とResult
という2つの構造体を定義し、XML文字列をResult
構造体にアンマーシャリングするプロセスを示しています。特に、Phone
フィールドが変更されないこと、<address>
要素が無視されること、Groups
フィールドがGroup>Value
というパスでマッピングされることが示されています。 - 変更:
ExampleMarshalIndent
関数内のxml.MarshalIndent
の呼び出しで、インデントの引数が"\t", "\t"
から" ", " "
に変更されました。また、// Output:
コメントブロックも新しいインデントに合わせて更新されています。 - 削除:
ExampleMarshalIndent
関数の上部にあった、XML出力のコメントブロックが削除されました。これは、// Output:
コメントブロックがその役割を果たすためです。
src/pkg/encoding/xml/read.go
- 削除:
Unmarshal
関数のドキュメントコメントから、XMLの例(Email
、Result
構造体の定義、XML入力、アンマーシャリング結果のコメント)が完全に削除されました。これは、これらの例がexample_test.go
に移動されたためです。
コアとなるコードの解説
ExampleUnmarshal
の追加
func ExampleUnmarshal() {
type Email struct {
Where string `xml:"where,attr"`
Addr string
}
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
}
p := Result{Name: "none", Phone: "none"}
data := `
<Person>
<FullName>Grace R. Emlin</FullName>
<Email where="home">
<Addr>gre@example.com</Addr>
</Email>
<Email where='work'>
<Addr>gre@work.com</Addr>
</Email>
<Group>
<Value>Friends</Value>
<Value>Squash</Value>
</Group>
<Address>123 Main Street</Address>
</Person>
`
err := xml.Unmarshal([]byte(data), &p)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("XMLName: %#v\\n", p.XMLName)
fmt.Printf("Name: %q\\n", p.Name)
fmt.Printf("Phone: %q\\n", p.Phone)
fmt.Printf("Email: %v\\n", p.Email)
fmt.Printf("Groups: %v\\n", p.Groups)
// Output:
// XMLName: xml.Name{Space:"", Local:"Person"}
// Name: "Grace R. Emlin"
// Phone: "none"
// Email: [{home gre@example.com} {work gre@work.com}]
// Groups: [Friends Squash]
}
この新しい ExampleUnmarshal
関数は、xml.Unmarshal
の動作を具体的に示しています。
Email
構造体は、XML属性 (where,attr
) と要素 (Addr
) の両方をどのようにマッピングするかを示します。Result
構造体は、XMLName
を使ってルート要素名を指定する方法、FullName
のようにXML要素名と異なるフィールド名にマッピングする方法、Phone
のようにXMLに存在しないフィールドが変更されないこと、Email
のように複数の要素をスライスにマッピングする方法、そしてGroup>Value
のようにネストされた要素パスをGroups
スライスにマッピングする方法を示しています。Address
要素はResult
構造体にマッピングするフィールドがないため、アンマーシャリング時に無視されることが示されています。// Output:
コメントブロックは、この例を実行した際の期待される標準出力を正確に定義しており、go test
による自動検証を可能にしています。
MarshalIndent
のインデント修正
func ExampleMarshalIndent() {
type Person struct {
XMLName xml.Name `xml:"person"`
Id int `xml:"id,attr"`
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
Age int
Married bool
Comment string `xml:",comment"`
}
v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}
v.Comment = " Need more fields. "
output, err := xml.MarshalIndent(v, " ", " ") // 変更点
if err != nil {
fmt.Printf("error: %v\\n", err)
}
os.Stdout.Write(output)
// Output: // 変更点
// <person id="13">
// <name>
// <first>John</first>
// <last>Doe</last>
// </name>
// <age>42</age>
// <Married>false</Married>
// <!-- Need more fields. -->
// </person>
}
xml.MarshalIndent(v, " ", " ")
の呼び出しは、生成されるXMLのインデントを制御します。
- 最初の引数
" "
は、各要素の開始タグの前に付加されるプレフィックスです。ここでは2つのスペースが指定されています。 - 2番目の引数
" "
は、ネストされた要素のインデントに使用される文字列です。ここでは4つのスペースが指定されています。
この変更により、生成されるXMLのインデントがタブからスペースベースに変わり、Goの一般的なコーディングスタイルガイドラインに準拠するようになりました。// Output:
コメントも、この新しいインデントに合わせて更新されています。
関連リンク
- Go CL 5671062: https://golang.org/cl/5671062
参考にした情報源リンク
- GitHubコミットページ: https://github.com/golang/go/commit/133c6bf77fffcbfa38ed58cf06808b38bbc374e0
- Go言語
encoding/xml
パッケージ公式ドキュメント (現在のバージョン): https://pkg.go.dev/encoding/xml - Go言語
Example
関数に関するドキュメント: https://go.dev/blog/examples