[インデックス 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