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

[インデックス 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/jsonencoding/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 の変更

  1. IgnoreTest 構造体の追加:

    type IgnoreTest struct {
        PublicSecret string `xml:"-"`
    }
    

    この新しい構造体は、PublicSecret というフィールドを持ち、そのフィールドに xml:"-" という構造体タグが付与されています。これは、このフィールドがXMLのマーシャリングおよびアンマーシャリングの対象から除外されるべきであることを示します。

  2. 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 の変更

  1. 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のマーシャリングおよびアンマーシャリングの対象外となります。
  2. コメントの削除:

    -	// TODO:
    -	//fIgnore
    

    以前は fIgnore というコメントアウトされたTODO項目がありましたが、今回の変更で xml:"-" による無視機能が実装されたため、このTODOは不要となり削除されました。

これらの変更により、Goの encoding/xml パッケージは、開発者が構造体タグを使って特定のフィールドをXML変換から簡単に除外できるようになり、より柔軟なXML処理が可能になりました。

関連リンク

参考にした情報源リンク