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

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

このコミットは、Go言語の標準ライブラリ encoding/xml パッケージ内の marshal.go および marshal_test.go ファイルに変更を加えています。具体的には、XMLエンコーダがXML宣言(<?xml ...?>)を正しく処理できるようにするための修正と、それに対応するテストの追加が行われています。

コミット

commit 92440fb5bd43912e363f32409bba5d6880356d60
Author: Jason Del Ponte <delpontej@gmail.com>
Date:   Mon May 12 23:35:56 2014 -0400

    encoding/xml: fix to allow xml declaration with EncodeToken
    
    This changes allows the first token encoded to be a xml declaration. A ProcInst with target of xml. Any other ProcInst after that with a target of xml will fail
    
    Fixes #7380.
    
    LGTM=rsc
    R=golang-codereviews, rsc
    CC=golang-codereviews
    https://golang.org/cl/72410043

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

https://github.com/golang/go/commit/92440fb5bd43912e363f32409bba5d6880356d60

元コミット内容

encoding/xml: fix to allow xml declaration with EncodeToken

この変更は、エンコードされる最初のトークンがXML宣言であることを許可します。ターゲットが xml の処理命令(ProcInst)がこれに該当します。それ以降にターゲットが xml の処理命令があった場合、それは失敗します。

Fixes #7380.

変更の背景

このコミットは、Goの encoding/xml パッケージがXML宣言を正しく処理できないというバグ(Issue #7380)を修正するために行われました。

XML宣言(例: <?xml version="1.0" encoding="UTF-8"?>)は、XMLドキュメントの冒頭に記述される特別な処理命令(Processing Instruction, ProcInst)です。これはドキュメントのバージョンやエンコーディングなどの情報を提供します。

encoding/xml パッケージの Encoder.EncodeToken メソッドは、XMLトークンをエンコードするための低レベルなAPIです。しかし、以前の実装では、ターゲットが xml である ProcInst をエンコードしようとすると、それがXML宣言であってもエラーとなっていました。これは、xml をターゲットとする ProcInst がXML宣言として特別扱いされるべきであるにもかかわらず、一般的な ProcInst と同じように扱われていたためです。

この問題により、ユーザーが EncodeToken を使ってXML宣言を含むXMLドキュメントを生成しようとすると、不必要なエラーが発生し、期待通りの動作が得られませんでした。このコミットは、この制約を緩和し、XML宣言がストリームの最初のトークンとしてのみ許可されるようにすることで、この問題を解決しています。

前提知識の解説

XML宣言 (XML Declaration)

XML宣言は、XMLドキュメントの最初の行に記述されるオプションの構成要素です。これは、XMLパーサに対してドキュメントのバージョン、文字エンコーディング、スタンドアロン宣言(外部DTDを参照するかどうか)などの情報を提供します。

例: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>

XML宣言は、厳密にはXMLの処理命令(Processing Instruction)の一種ですが、特別な意味を持ちます。XML仕様では、XML宣言はドキュメントの最初の非コメント、非空白文字である必要があり、一度しか出現してはならないと定められています。

処理命令 (Processing Instruction, ProcInst)

XMLの処理命令は、アプリケーションに特定の情報や指示を伝えるためのメカニズムです。構文は <?target instruction?> の形式を取ります。target は命令を受け取るアプリケーションを識別する名前で、instruction はそのアプリケーションが解釈するデータです。

XML宣言は、ターゲットが xml である処理命令として扱われますが、その位置と出現回数に厳格な制約があります。

Go言語の encoding/xml パッケージ

encoding/xml パッケージは、Go言語でXMLデータをエンコードおよびデコードするための機能を提供します。

  • xml.Encoder: XMLデータを書き込むための構造体です。NewEncoder 関数で作成され、EncodeEncodeElementEncodeToken などのメソッドを通じてXMLトークンを書き出します。
  • xml.Token: XMLドキュメントの構成要素(要素の開始タグ、終了タグ、文字データ、コメント、処理命令など)を表すインターフェースです。
  • xml.ProcInst: 処理命令を表す Token の実装です。Target(命令のターゲット名)と Inst(命令の内容)のフィールドを持ちます。
  • Encoder.EncodeToken(t Token) error: 指定されたXMLトークン t をエンコーダの出力ストリームに書き込みます。このメソッドは低レベルであり、通常は EncodeEncodeElement の内部で利用されますが、カスタムのXMLマーシャラなどで直接使用されることもあります。

技術的詳細

このコミットの技術的な核心は、encoding/xml パッケージが ProcInst を処理する際のロジックの変更にあります。

以前の EncodeToken の実装では、ProcInstTargetxml である場合、無条件にエラーを返すか、または isNameString 関数による一般的なターゲット名の検証に失敗していました。これは、XML宣言が xml をターゲットとする ProcInst であるにもかかわらず、その特別な性質が考慮されていなかったためです。

XML仕様では、XML宣言はドキュメントの最初のトークンとしてのみ許可され、それ以降に xml をターゲットとする ProcInst が出現することは許されません。このコミットは、この仕様に準拠するように EncodeToken の動作を調整します。

具体的には、以下のロジックが導入されました。

  1. EncodeToken が呼び出された際に、エンコーダのバッファが空(つまり、まだ何も書き込まれていない状態)であり、かつエンコードしようとしているトークンがターゲットが xmlProcInst である場合、これをXML宣言として許可します。
  2. しかし、エンコーダのバッファに既にデータが存在する(つまり、最初のトークンではない)状態で、ターゲットが xmlProcInst をエンコードしようとすると、エラーを返します。これは、XML宣言が最初のトークンとしてのみ許可されるというXMLの規則を強制するためです。
  3. その他の ProcInst(ターゲットが xml ではないもの)については、引き続き isNameString によるターゲット名の検証が行われ、不正なターゲット名であればエラーとなります。

この変更により、ユーザーは EncodeToken を使ってXML宣言をXMLドキュメントの冒頭に正しく出力できるようになり、同時にXML仕様に違反するような不正なXML宣言の繰り返しを防ぐことができます。

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

変更は主に以下の2つのファイルで行われています。

  1. src/pkg/encoding/xml/marshal.go: Encoder.EncodeToken メソッド内の ProcInst の処理ロジックが変更されました。
  2. src/pkg/encoding/xml/marshal_test.go: EncodeToken の新しい動作を検証するためのテストケースが追加されました。特に、XML宣言のエンコードと、それ以外の xml ターゲットの ProcInst のエンコードが禁止されることを確認するテストが追加されています。

コアとなるコードの解説

src/pkg/encoding/xml/marshal.go の変更

--- a/src/pkg/encoding/xml/marshal.go
+++ b/src/pkg/encoding/xml/marshal.go
@@ -184,10 +184,12 @@ var (
 // EncodeToken does not call Flush, because usually it is part of a larger operation
 // such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
 // during those), and those will call Flush when finished.
-//
 // Callers that create an Encoder and then invoke EncodeToken directly, without
 // using Encode or EncodeElement, need to call Flush when finished to ensure
 // that the XML is written to the underlying writer.
+//
+// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
+// in the stream.
 func (enc *Encoder) EncodeToken(t Token) error {
  	p := &enc.p
  	switch t := t.(type) {
@@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
  	\tp.WriteString("-->")
  	\treturn p.cachedWriteError()
  	case ProcInst:
-\t\tif t.Target == "xml" || !isNameString(t.Target) {
+\t\t// First token to be encoded which is also a ProcInst with target of xml
+\t\t// is the xml declaration.  The only ProcInst where target of xml is allowed.
+\t\tif t.Target == "xml" && p.Buffered() != 0 {
+\t\t\treturn fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
+\t\t}
+\t\tif !isNameString(t.Target) {
 \t\t\treturn fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
 \t\t}
 \t\tif bytes.Contains(t.Inst, endProcInst) {
  • コメントの追加: EncodeToken のドキュメンテーションに、"xml" をターゲットとする ProcInst はストリームの最初のトークンとしてのみ許可されるという新しいルールが追加されました。
  • ProcInst 処理ロジックの変更:
    • case ProcInst: ブロック内で、新しい条件 t.Target == "xml" && p.Buffered() != 0 が追加されました。
      • t.Target == "xml": 処理命令のターゲットが "xml" であることをチェックします。
      • p.Buffered() != 0: エンコーダの内部バッファに既にデータが書き込まれているかどうかをチェックします。p.Buffered() はバッファ内のバイト数を返します。これが0でないということは、この ProcInst が最初のトークンではないことを意味します。
    • この条件が真の場合(つまり、最初のトークンではないのに xml ターゲットの ProcInst をエンコードしようとした場合)、"xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded" というエラーが返されます。これにより、XML宣言が最初のトークンとしてのみ許可されるというXMLの規則が強制されます。
    • 元の t.Target == "xml" || !isNameString(t.Target) という条件は !isNameString(t.Target) に変更されました。これは、xml ターゲットの ProcInst の特別な処理が上記の新ロジックでカバーされるため、一般的なターゲット名の検証のみを行うように簡略化されたことを意味します。

src/pkg/encoding/xml/marshal_test.go の変更

--- a/src/pkg/encoding/xml/marshal_test.go
+++ b/src/pkg/encoding/xml/marshal_test.go
@@ -1203,7 +1203,7 @@ var encodeTokenTests = []struct {
 	{Comment("foo"), "<!--foo-->", true},
 	{Comment("foo-->"), "", false},
 	{ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
-\t{ProcInst{"xml", []byte("Instruction")}, "", false},
+\t{ProcInst{"", []byte("Instruction")}, "", false},
 	{ProcInst{"Target", []byte("Instruction?>")}, "", false},
 	{Directive("foo"), "<!foo>", true},
 	{Directive("foo>"), "", false},
@@ -1230,3 +1230,37 @@ func TestEncodeToken(t *testing.T) {
 		}
 	}\n}\n+\n+func TestProcInstEncodeToken(t *testing.T) {\n+\tvar buf bytes.Buffer\n+\tenc := NewEncoder(&buf)\n+\n+\tif err := enc.EncodeToken(ProcInst{\"xml\", []byte(\"Instruction\")}); err != nil {\n+\t\tt.Fatalf(\"enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s\", err)\n+\t}\n+\n+\tif err := enc.EncodeToken(ProcInst{\"Target\", []byte(\"Instruction\")}); err != nil {\n+\t\tt.Fatalf(\"enc.EncodeToken: expected to be able to add non-xml target ProcInst\")\n+\t}\n+\n+\tif err := enc.EncodeToken(ProcInst{\"xml\", []byte(\"Instruction\")}); err == nil {\n+\t\tt.Fatalf(\"enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token\")\n+\t}\n+}\n+\n+func TestDecodeEncode(t *testing.T) {\n+\tvar in, out bytes.Buffer\n+\tin.WriteString(`<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n+<?Target Instruction?>\n+<root>\n+</root>\t\n+`)\n+\tdec := NewDecoder(&in)\n+\tenc := NewEncoder(&out)\n+\tfor tok, err := dec.Token(); err == nil; tok, err = dec.Token() {\n+\t\terr = enc.EncodeToken(tok)\n+\t\tif err != nil {\n+\t\t\tt.Fatalf(\"enc.EncodeToken: Unable to encode token (%#v), %d\", tok, err)\n+\t\t}\n+\t}\n+}\n```

*   **`encodeTokenTests` の修正**:
    *   `{ProcInst{"xml", []byte("Instruction")}, "", false},` が `{ProcInst{"", []byte("Instruction")}, "", false},` に変更されました。これは、`xml` ターゲットの `ProcInst` が常にエンコードに失敗するわけではなく、最初のトークンであれば成功するようになったため、テストケースを修正したものです。空のターゲットを持つ `ProcInst` は不正なため、引き続き失敗するテストとして残されています。
*   **`TestProcInstEncodeToken` の追加**:
    *   この新しいテスト関数は、`xml` ターゲットの `ProcInst` の新しい動作を具体的に検証します。
    *   最初の `enc.EncodeToken(ProcInst{"xml", []byte("Instruction")})` は、XML宣言として最初のトークンでエンコードが成功することを期待します。
    *   次に `enc.EncodeToken(ProcInst{"Target", []byte("Instruction")})` は、通常の `ProcInst` が引き続きエンコードできることを確認します。
    *   最後に `enc.EncodeToken(ProcInst{"xml", []byte("Instruction")})` は、最初のトークンではない `xml` ターゲットの `ProcInst` がエンコードに失敗することを期待します。
*   **`TestDecodeEncode` の追加**:
    *   このテストは、XML宣言を含むXMLドキュメントをデコードし、その後エンコードし直すというエンドツーエンドのシナリオを検証します。
    *   入力XMLにはXML宣言と通常の処理命令が含まれており、これらが `DecodeToken` で正しく読み取られ、`EncodeToken` でエラーなく書き出されることを確認します。これにより、XML宣言の処理がデコードとエンコードの両方で一貫して機能することが保証されます。

これらの変更により、`encoding/xml` パッケージはXML宣言の処理に関してXML仕様に準拠し、より堅牢で正確なXMLエンコーディング機能を提供するようになりました。

## 関連リンク

*   Go Issue #7380: [https://github.com/golang/go/issues/7380](https://github.com/golang/go/issues/7380)
*   Go CL 72410043: [https://golang.org/cl/72410043](https://golang.org/cl/72410043)

## 参考にした情報源リンク

*   XML 1.0 (Fifth Edition) - Processing Instructions: [https://www.w3.org/TR/xml/#sec-pi](https://www.w3.org/TR/xml/#sec-pi)
*   XML 1.0 (Fifth Edition) - XML Declaration: [https://www.w3.org/TR/xml/#sec-prolog-dtd](https://www.w3.org/TR/xml/#sec-prolog-dtd)
*   Go `encoding/xml` package documentation: [https://pkg.go.dev/encoding/xml](https://pkg.go.dev/encoding/xml)
*   Go `bytes` package documentation: [https://pkg.go.dev/bytes](https://pkg.go.dev/bytes)
*   Go `fmt` package documentation: [https://pkg.go.dev/fmt](https://pkg.go.dev/fmt)
*   Go `testing` package documentation: [https://pkg.go.dev/testing](https://pkg.go.dev/testing)
*   Go `strings` package documentation: [https://pkg.go.dev/strings](https://pkg.go.dev/strings) (indirectly used by `bytes.Contains`)```markdown
# [インデックス 19340] ファイルの概要

このコミットは、Go言語の標準ライブラリ `encoding/xml` パッケージ内の `marshal.go` および `marshal_test.go` ファイルに変更を加えています。具体的には、XMLエンコーダがXML宣言(`<?xml ...?>`)を正しく処理できるようにするための修正と、それに対応するテストの追加が行われています。

## コミット

commit 92440fb5bd43912e363f32409bba5d6880356d60 Author: Jason Del Ponte delpontej@gmail.com Date: Mon May 12 23:35:56 2014 -0400

encoding/xml: fix to allow xml declaration with EncodeToken

This changes allows the first token encoded to be a xml declaration. A ProcInst with target of xml. Any other ProcInst after that with a target of xml will fail

Fixes #7380.

LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/72410043

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

[https://github.com/golang/go/commit/92440fb5bd43912e363f32409bba5d6880356d60](https://github.com/golang/go/commit/92440fb5bd43912e363f32409bba5d6880356d60)

## 元コミット内容

`encoding/xml: fix to allow xml declaration with EncodeToken`

この変更は、エンコードされる最初のトークンがXML宣言であることを許可します。ターゲットが `xml` の処理命令(ProcInst)がこれに該当します。それ以降にターゲットが `xml` の処理命令があった場合、それは失敗します。

Fixes #7380.

## 変更の背景

このコミットは、Goの `encoding/xml` パッケージがXML宣言を正しく処理できないというバグ(Issue #7380)を修正するために行われました。

XML宣言(例: `<?xml version="1.0" encoding="UTF-8"?>`)は、XMLドキュメントの冒頭に記述される特別な処理命令(Processing Instruction, ProcInst)です。これはドキュメントのバージョンやエンコーディングなどの情報を提供します。

`encoding/xml` パッケージの `Encoder.EncodeToken` メソッドは、XMLトークンをエンコードするための低レベルなAPIです。しかし、以前の実装では、ターゲットが `xml` である `ProcInst` をエンコードしようとすると、それがXML宣言であってもエラーとなっていました。これは、`xml` をターゲットとする `ProcInst` がXML宣言として特別扱いされるべきであるにもかかわらず、一般的な `ProcInst` と同じように扱われていたためです。

この問題により、ユーザーが `EncodeToken` を使ってXML宣言を含むXMLドキュメントを生成しようとすると、不必要なエラーが発生し、期待通りの動作が得られませんでした。このコミットは、この制約を緩和し、XML宣言がストリームの最初のトークンとしてのみ許可されるようにすることで、この問題を解決しています。

## 前提知識の解説

### XML宣言 (XML Declaration)

XML宣言は、XMLドキュメントの最初の行に記述されるオプションの構成要素です。これは、XMLパーサに対してドキュメントのバージョン、文字エンコーディング、スタンドアロン宣言(外部DTDを参照するかどうか)などの情報を提供します。

例: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`

XML宣言は、厳密にはXMLの処理命令(Processing Instruction)の一種ですが、特別な意味を持ちます。XML仕様では、XML宣言はドキュメントの最初の非コメント、非空白文字である必要があり、一度しか出現してはならないと定められています。

### 処理命令 (Processing Instruction, ProcInst)

XMLの処理命令は、アプリケーションに特定の情報や指示を伝えるためのメカニズムです。構文は `<?target instruction?>` の形式を取ります。`target` は命令を受け取るアプリケーションを識別する名前で、`instruction` はそのアプリケーションが解釈するデータです。

XML宣言は、ターゲットが `xml` である処理命令として扱われますが、その位置と出現回数に厳格な制約があります。

### Go言語の `encoding/xml` パッケージ

`encoding/xml` パッケージは、Go言語でXMLデータをエンコードおよびデコードするための機能を提供します。

*   **`xml.Encoder`**: XMLデータを書き込むための構造体です。`NewEncoder` 関数で作成され、`Encode`、`EncodeElement`、`EncodeToken` などのメソッドを通じてXMLトークンを書き出します。
*   **`xml.Token`**: XMLドキュメントの構成要素(要素の開始タグ、終了タグ、文字データ、コメント、処理命令など)を表すインターフェースです。
*   **`xml.ProcInst`**: 処理命令を表す `Token` の実装です。`Target`(命令のターゲット名)と `Inst`(命令の内容)のフィールドを持ちます。
*   **`Encoder.EncodeToken(t Token) error`**: 指定されたXMLトークン `t` をエンコーダの出力ストリームに書き込みます。このメソッドは低レベルであり、通常は `Encode` や `EncodeElement` の内部で利用されますが、カスタムのXMLマーシャラなどで直接使用されることもあります。

## 技術的詳細

このコミットの技術的な核心は、`encoding/xml` パッケージが `ProcInst` を処理する際のロジックの変更にあります。

以前の `EncodeToken` の実装では、`ProcInst` の `Target` が `xml` である場合、無条件にエラーを返すか、または `isNameString` 関数による一般的なターゲット名の検証に失敗していました。これは、XML宣言が `xml` をターゲットとする `ProcInst` であるにもかかわらず、その特別な性質が考慮されていなかったためです。

XML仕様では、XML宣言はドキュメントの最初のトークンとしてのみ許可され、それ以降に `xml` をターゲットとする `ProcInst` が出現することは許されません。このコミットは、この仕様に準拠するように `EncodeToken` の動作を調整します。

具体的には、以下のロジックが導入されました。

1.  `EncodeToken` が呼び出された際に、エンコーダのバッファが空(つまり、まだ何も書き込まれていない状態)であり、かつエンコードしようとしているトークンがターゲットが `xml` の `ProcInst` である場合、これをXML宣言として許可します。
2.  しかし、エンコーダのバッファに既にデータが存在する(つまり、最初のトークンではない)状態で、ターゲットが `xml` の `ProcInst` をエンコードしようとすると、エラーを返します。これは、XML宣言が最初のトークンとしてのみ許可されるというXMLの規則を強制するためです。
3.  その他の `ProcInst`(ターゲットが `xml` ではないもの)については、引き続き `isNameString` によるターゲット名の検証が行われ、不正なターゲット名であればエラーとなります。

この変更により、ユーザーは `EncodeToken` を使ってXML宣言をXMLドキュメントの冒頭に正しく出力できるようになり、同時にXML仕様に違反するような不正なXML宣言の繰り返しを防ぐことができます。

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

変更は主に以下の2つのファイルで行われています。

1.  `src/pkg/encoding/xml/marshal.go`: `Encoder.EncodeToken` メソッド内の `ProcInst` の処理ロジックが変更されました。
2.  `src/pkg/encoding/xml/marshal_test.go`: `EncodeToken` の新しい動作を検証するためのテストケースが追加されました。特に、XML宣言のエンコードと、それ以外の `xml` ターゲットの `ProcInst` のエンコードが禁止されることを確認するテストが追加されています。

## コアとなるコードの解説

### `src/pkg/encoding/xml/marshal.go` の変更

```diff
--- a/src/pkg/encoding/xml/marshal.go
+++ b/src/pkg/encoding/xml/marshal.go
@@ -184,10 +184,12 @@ var (
 // EncodeToken does not call Flush, because usually it is part of a larger operation
 // such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
 // during those), and those will call Flush when finished.
-//
 // Callers that create an Encoder and then invoke EncodeToken directly, without
 // using Encode or EncodeElement, need to call Flush when finished to ensure
 // that the XML is written to the underlying writer.
+//
+// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
+// in the stream.
 func (enc *Encoder) EncodeToken(t Token) error {
  	p := &enc.p
  	switch t := t.(type) {
@@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
  	\tp.WriteString("-->")
  	\treturn p.cachedWriteError()
  	case ProcInst:
-\t\tif t.Target == "xml" || !isNameString(t.Target) {
+\t\t// First token to be encoded which is also a ProcInst with target of xml
+\t\t// is the xml declaration.  The only ProcInst where target of xml is allowed.
+\t\tif t.Target == "xml" && p.Buffered() != 0 {
+\t\t\treturn fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
+\t\t}
+\t\tif !isNameString(t.Target) {
 \t\t\treturn fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
 \t\t}
 \t\tif bytes.Contains(t.Inst, endProcInst) {
  • コメントの追加: EncodeToken のドキュメンテーションに、"xml" をターゲットとする ProcInst はストリームの最初のトークンとしてのみ許可されるという新しいルールが追加されました。
  • ProcInst 処理ロジックの変更:
    • case ProcInst: ブロック内で、新しい条件 t.Target == "xml" && p.Buffered() != 0 が追加されました。
      • t.Target == "xml": 処理命令のターゲットが "xml" であることをチェックします。
      • p.Buffered() != 0: エンコーダの内部バッファに既にデータが書き込まれているかどうかをチェックします。p.Buffered() はバッファ内のバイト数を返します。これが0でないということは、この ProcInst が最初のトークンではないことを意味します。
    • この条件が真の場合(つまり、最初のトークンではないのに xml ターゲットの ProcInst をエンコードしようとした場合)、"xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded" というエラーが返されます。これにより、XML宣言が最初のトークンとしてのみ許可されるというXMLの規則が強制されます。
    • 元の t.Target == "xml" || !isNameString(t.Target) という条件は !isNameString(t.Target) に変更されました。これは、xml ターゲットの ProcInst の特別な処理が上記の新ロジックでカバーされるため、一般的なターゲット名の検証のみを行うように簡略化されたことを意味します。

src/pkg/encoding/xml/marshal_test.go の変更

--- a/src/pkg/encoding/xml/marshal_test.go
+++ b/src/pkg/encoding/xml/marshal_test.go
@@ -1203,7 +1203,7 @@ var encodeTokenTests = []struct {
 	{Comment("foo"), "<!--foo-->", true},
 	{Comment("foo-->"), "", false},
 	{ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
-\t{ProcInst{"xml", []byte("Instruction")}, "", false},
+\t{ProcInst{"", []byte("Instruction")}, "", false},
 	{ProcInst{"Target", []byte("Instruction?>")}, "", false},
 	{Directive("foo"), "<!foo>", true},
 	{Directive("foo>"), "", false},
@@ -1230,3 +1230,37 @@ func TestEncodeToken(t *testing.T) {
 		}
 	}\n}\n+\n+func TestProcInstEncodeToken(t *testing.T) {\n+\tvar buf bytes.Buffer\n+\tenc := NewEncoder(&buf)\n+\n+\tif err := enc.EncodeToken(ProcInst{\"xml\", []byte(\"Instruction\")}); err != nil {\n+\t\tt.Fatalf(\"enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s\", err)\n+\t}\n+\n+\tif err := enc.EncodeToken(ProcInst{\"Target\", []byte(\"Instruction\")}); err != nil {\n+\t\tt.Fatalf(\"enc.EncodeToken: expected to be able to add non-xml target ProcInst\")\n+\t}\n+\n+\tif err := enc.EncodeToken(ProcInst{\"xml\", []byte(\"Instruction\")}); err == nil {\n+\t\tt.Fatalf(\"enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token\")\n+\t}\n+}\n+\n+func TestDecodeEncode(t *testing.T) {\n+\tvar in, out bytes.Buffer\n+\tin.WriteString(`<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n+<?Target Instruction?>\n+<root>\n+</root>\t\n+`)\n+\tdec := NewDecoder(&in)\n+\tenc := NewEncoder(&out)\n+\tfor tok, err := dec.Token(); err == nil; tok, err = dec.Token() {\n+\t\terr = enc.EncodeToken(tok)\n+\t\tif err != nil {\n+\t\t\tt.Fatalf(\"enc.EncodeToken: Unable to encode token (%#v), %d\", tok, err)\n+\t\t}\n+\t}\n+}\n```

*   **`encodeTokenTests` の修正**:
    *   `{ProcInst{"xml", []byte("Instruction")}, "", false},` が `{ProcInst{"", []byte("Instruction")}, "", false},` に変更されました。これは、`xml` ターゲットの `ProcInst` が常にエンコードに失敗するわけではなく、最初のトークンであれば成功するようになったため、テストケースを修正したものです。空のターゲットを持つ `ProcInst` は不正なため、引き続き失敗するテストとして残されています。
*   **`TestProcInstEncodeToken` の追加**:
    *   この新しいテスト関数は、`xml` ターゲットの `ProcInst` の新しい動作を具体的に検証します。
    *   最初の `enc.EncodeToken(ProcInst{"xml", []byte("Instruction")})` は、XML宣言として最初のトークンでエンコードが成功することを期待します。
    *   次に `enc.EncodeToken(ProcInst{"Target", []byte("Instruction")})` は、通常の `ProcInst` が引き続きエンコードできることを確認します。
    *   最後に `enc.EncodeToken(ProcInst{"xml", []byte("Instruction")})` は、最初のトークンではない `xml` ターゲットの `ProcInst` がエンコードに失敗することを期待します。
*   **`TestDecodeEncode` の追加**:
    *   このテストは、XML宣言を含むXMLドキュメントをデコードし、その後エンコードし直すというエンドツーエンドのシナリオを検証します。
    *   入力XMLにはXML宣言と通常の処理命令が含まれており、これらが `DecodeToken` で正しく読み取られ、`EncodeToken` でエラーなく書き出されることを確認します。これにより、XML宣言の処理がデコードとエンコードの両方で一貫して機能することが保証されます。

これらの変更により、`encoding/xml` パッケージはXML宣言の処理に関してXML仕様に準拠し、より堅牢で正確なXMLエンコーディング機能を提供するようになりました。

## 関連リンク

*   Go Issue #7380: [https://github.com/golang/go/issues/7380](https://github.com/golang/go/issues/7380)
*   Go CL 72410043: [https://golang.org/cl/72410043](https://golang.org/cl/72410043)

## 参考にした情報源リンク

*   XML 1.0 (Fifth Edition) - Processing Instructions: [https://www.w3.org/TR/xml/#sec-pi](https://www.w3.org/TR/xml/#sec-pi)
*   XML 1.0 (Fifth Edition) - XML Declaration: [https://www.w3.org/TR/xml/#sec-prolog-dtd](https://www.w3.org/TR/xml/#sec-prolog-dtd)
*   Go `encoding/xml` package documentation: [https://pkg.go.dev/encoding/xml](https://pkg.go.dev/encoding/xml)
*   Go `bytes` package documentation: [https://pkg.go.dev/bytes](https://pkg.go.dev/bytes)
*   Go `fmt` package documentation: [https://pkg.go.dev/fmt](https://pkg.go.dev/fmt)
*   Go `testing` package documentation: [https://pkg.go.dev/testing](https://pkg.go.dev/testing)
*   Go `strings` package documentation: [https://pkg.go.dev/strings](https://pkg.go.dev/strings) (indirectly used by `bytes.Contains`)