[インデックス 11326] ファイルの概要
このコミットは、Go言語の標準ライブラリである encoding/xml
パッケージにおける機能改善に関するものです。encoding/xml
パッケージは、Goの構造体とXMLデータの間のマーシャリング(Go構造体からXMLへの変換)およびアンマーシャリング(XMLからGo構造体への変換)を扱うための機能を提供します。
変更が加えられたファイルは以下の通りです。
src/pkg/encoding/xml/marshal_test.go
:encoding/xml
パッケージのマーシャリング機能に関するテストファイルです。新しい機能の動作検証のためのテストケースが追加されています。src/pkg/encoding/xml/typeinfo.go
:encoding/xml
パッケージがGoの型情報を解析し、XMLとのマッピングを決定するための内部ロジックが含まれるファイルです。今回の変更の核心部分であり、xml:"-"
タグの処理が追加されています。
コミット
encoding/xml: support ignoring fields with "-"
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5564045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5fde5cd5cb4e62b6c3d5188b2bfd5e25a02317d2
元コミット内容
encoding/xml: support ignoring fields with "-"
変更の背景
Goの encoding/xml
パッケージでは、Goの構造体フィールドをXML要素や属性にマッピングする際に、構造体タグ(struct tag)を使用してその挙動を制御します。しかし、このコミット以前は、特定のフィールドをXMLのマーシャリングやアンマーシャリングの対象から完全に除外する直接的なメカニズムがありませんでした。
例えば、構造体内に内部的な目的でのみ使用されるフィールドや、セキュリティ上の理由からXML出力に含めたくない機密情報を含むフィールドがある場合、それらのフィールドが意図せずXMLに現れてしまう可能性がありました。このような場合、開発者はフィールドを非公開(unexported)にするか、カスタムのマーシャリング/アンマーシャリングロジックを実装するなどの回避策を講じる必要がありました。
このコミットは、xml:"-"
という新しい構造体タグのサポートを追加することで、この問題を解決し、開発者がより簡潔かつ明示的にフィールドを無視できるようにすることを目的としています。これにより、XMLのスキーマとGoの構造体の間のマッピングをより柔軟に制御できるようになります。
前提知識の解説
Go言語の構造体タグ (Struct Tags)
Go言語では、構造体のフィールドに「タグ」と呼ばれるメタデータを付与することができます。タグは文字列リテラルで記述され、リフレクションAPIを通じて実行時にアクセス可能です。encoding/json
や encoding/xml
のような標準ライブラリは、このタグを利用して、構造体フィールドと外部データ形式(JSON、XMLなど)との間のマッピングルールを定義します。
例:
type Person struct {
Name string `json:"person_name" xml:"name"`
Age int `json:"age,omitempty"`
}
上記の例では、Name
フィールドはJSONでは person_name
、XMLでは name
というキーにマッピングされます。Age
フィールドはJSONでは age
にマッピングされ、値がゼロ値(この場合は0)の場合はJSON出力から省略されます (omitempty
)。
encoding/xml
パッケージ
encoding/xml
パッケージは、Goの構造体とXMLドキュメントの間でデータを変換するための機能を提供します。
- マーシャリング (Marshaling): Goの構造体のインスタンスをXMLデータに変換するプロセスです。
xml.Marshal
関数がこれを行います。 - アンマーシャリング (Unmarshaling): XMLデータをGoの構造体のインスタンスに変換するプロセスです。
xml.Unmarshal
関数がこれを行います。
デフォルトでは、encoding/xml
は構造体の公開(exported)フィールドをXML要素または属性にマッピングしようとします。マッピングのルールは、フィールド名や構造体タグによって制御されます。
技術的詳細
このコミットの技術的な核心は、encoding/xml
パッケージがGoの構造体フィールドをXMLにマッピングする際の内部ロジックに xml:"-"
タグの認識を追加した点にあります。
encoding/xml
パッケージは、Goの reflect
パッケージを使用して構造体の型情報を実行時に検査します。この検査プロセスの中で、各フィールドがXMLにどのようにマッピングされるべきかを決定するための「型情報 (type info)」を構築します。
変更前は、typeinfo.go
内の getTypeInfo
関数がフィールドを処理する際に、非公開フィールド(f.PkgPath != ""
)のみをスキップしていました。非公開フィールドは、パッケージ外からアクセスできないため、通常はXMLマーシャリングの対象外とされます。
このコミットでは、このロジックに || f.Tag.Get("xml") == "-"
という条件が追加されました。これにより、フィールドが非公開であるか、またはそのフィールドの xml
タグの値がハイフン (-
) である場合に、そのフィールドがXMLマッピングの対象から除外されるようになりました。
具体的には、xml:"-"
タグを持つフィールドは、getTypeInfo
関数が構造体のフィールドを走査する際に、そのフィールドに関する型情報を生成しないようにスキップされます。結果として、このフィールドはマーシャリング時にはXML出力に含まれず、アンマーシャリング時にはXML入力からこのフィールドに対応するデータが読み込まれることもありません。
marshal_test.go
に追加されたテストケースは、この新しい挙動を検証しています。IgnoreTest
構造体の PublicSecret
フィールドに xml:"-"
タグを付与し、この構造体をマーシャリングした際に、PublicSecret
フィールドがXML出力に含まれないことを確認しています。
コアとなるコードの変更箇所
src/pkg/encoding/xml/marshal_test.go
--- a/src/pkg/encoding/xml/marshal_test.go
+++ b/src/pkg/encoding/xml/marshal_test.go
@@ -188,6 +188,10 @@ type PresenceTest struct {
Exists *struct{}\n }\n \n+type IgnoreTest struct {\n+\tPublicSecret string `xml:\"-\"`\n+}\n+\n type MyBytes []byte\n \n type Data struct {\n@@ -592,6 +596,22 @@ var marshalTests = []struct {\n \t\t},\n \t\tExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,\n \t},\n+\n+\t// Test ignoring fields via \"-\" tag\n+\t{\n+\t\tExpectXML: `<IgnoreTest></IgnoreTest>`,\n+\t\tValue: &IgnoreTest{},\n+\t},\n+\t{\n+\t\tExpectXML: `<IgnoreTest></IgnoreTest>`,\n+\t\tValue: &IgnoreTest{PublicSecret: \"can\'t tell\"},\n+\t\tMarshalOnly: true,\n+\t},\n+\t{\n+\t\tExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,\n+\t\tValue: &IgnoreTest{},\n+\t\tUnmarshalOnly: true,\n+\t},\n }\n \n func TestMarshal(t *testing.T) {\ndiff --git a/src/pkg/encoding/xml/typeinfo.go b/src/pkg/encoding/xml/typeinfo.go
src/pkg/encoding/xml/typeinfo.go
--- a/src/pkg/encoding/xml/typeinfo.go
+++ b/src/pkg/encoding/xml/typeinfo.go
@@ -37,7 +37,6 @@ const (
fAny
// TODO:
- //fIgnore
//fOmitEmpty
fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny
@@ -62,7 +61,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
tn := typ.NumField()
for i := 0; i < tn; i++ {
f := typ.Field(i)
- if f.PkgPath != "" {
+ if f.PkgPath != "" || f.Tag.Get("xml") == "-" {
continue // Private field
}
コアとなるコードの解説
src/pkg/encoding/xml/marshal_test.go
の変更
-
IgnoreTest
構造体の追加:type IgnoreTest struct { PublicSecret string `xml:"-"` }
この新しい構造体は、
PublicSecret
というフィールドを持ち、そのフィールドにxml:"-"
という構造体タグが付与されています。これは、このフィールドがXMLのマーシャリングおよびアンマーシャリングの対象から除外されるべきであることを示します。 -
marshalTests
にテストケースを追加:marshalTests
は、encoding/xml
パッケージのマーシャリング/アンマーシャリングの挙動を検証するためのテストデータスライスです。以下の3つの新しいテストケースが追加されました。-
ケース1 (基本の無視テスト):
{ ExpectXML: `<IgnoreTest></IgnoreTest>`, Value: &IgnoreTest{}, },
IgnoreTest{}
をマーシャリングした際に、PublicSecret
フィールドがXMLに含まれず、空の<IgnoreTest></IgnoreTest>
が生成されることを期待しています。これはxml:"-"
タグが正しく機能していることを示します。 -
ケース2 (値を持つフィールドの無視テスト):
{ ExpectXML: `<IgnoreTest></IgnoreTest>`, Value: &IgnoreTest{PublicSecret: "can't tell"}, MarshalOnly: true, },
PublicSecret
フィールドに具体的な値が設定されている場合でも、マーシャリング時にはその値がXMLに含まれず、やはり空の<IgnoreTest></IgnoreTest>
が生成されることを確認しています。MarshalOnly: true
は、このテストケースがマーシャリングのみを対象としていることを示します。 -
ケース3 (アンマーシャリング時の無視テスト):
{ ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`, Value: &IgnoreTest{}, UnmarshalOnly: true, },
このテストケースは、XML入力に
<PublicSecret>
要素が含まれている場合でも、xml:"-"
タグが付与されたPublicSecret
フィールドにはその値がアンマーシャルされないことを検証しています。UnmarshalOnly: true
は、このテストケースがアンマーシャリングのみを対象としていることを示します。
-
src/pkg/encoding/xml/typeinfo.go
の変更
-
getTypeInfo
関数の条件変更:- if f.PkgPath != "" { + if f.PkgPath != "" || f.Tag.Get("xml") == "-" { continue // Private field }
この変更が、
xml:"-"
タグのサポートの核心です。f.PkgPath != ""
は、フィールドが非公開(unexported)であるかどうかをチェックします。Goでは、フィールド名が小文字で始まる場合、そのフィールドは非公開となり、パッケージ外からはアクセスできません。encoding/xml
は通常、このようなフィールドを無視します。f.Tag.Get("xml") == "-"
は、フィールドに付与されたxml
タグの値がハイフン (-
) であるかどうかをチェックします。||
(論理OR) 演算子により、フィールドが非公開であるか、またはxml:"-"
タグを持つ場合に、continue
ステートメントが実行されます。continue
は、現在のフィールドの処理をスキップし、次のフィールドの処理に移ることを意味します。- これにより、
xml:"-"
タグを持つフィールドは、encoding/xml
パッケージの内部的な型情報構築プロセスから完全に除外され、結果としてXMLのマーシャリングおよびアンマーシャリングの対象外となります。
-
コメントの削除:
- // TODO: - //fIgnore
以前は
fIgnore
というコメントアウトされたTODO項目がありましたが、今回の変更でxml:"-"
による無視機能が実装されたため、このTODOは不要となり削除されました。
これらの変更により、Goの encoding/xml
パッケージは、開発者が構造体タグを使って特定のフィールドをXML変換から簡単に除外できるようになり、より柔軟なXML処理が可能になりました。
関連リンク
- Go CL 5564045: https://golang.org/cl/5564045
参考にした情報源リンク
- Go言語
encoding/xml
パッケージのドキュメント: https://pkg.go.dev/encoding/xml - Go言語の構造体タグに関する一般的な情報 (例:
json:"-"
の挙動など): https://go.dev/blog/json (JSONに関する記事ですが、構造体タグの概念は共通です) - Go言語のリフレクションに関する情報: https://go.dev/blog/laws-of-reflection