質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

2回答

410閲覧

【GO】構造体を扱った、JSON生成で困っています

Gunjirk

総合スコア23

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2020/06/29 07:08

実現したいこと

以下のJSONを出力する

//理想のJSON { "command": "ENT", "table": [ { "table_name": "basic", "clientid": 0, "server": "basic" }, { "table_name": "contents", "clientid": 0, "time_control": "0" } ] }
//現在のJSON { "command": "ENT", "table": [ { "Table1": { "table_name": "basic", "clientid": 0, "server": "basic" }, "Table2": { "table_name": "contents", "clientid": 0, "time_control": 0 } } ] }

"Table1": {
"Table2": {
の部分が不要なのですが、どうしても消せません。。。

プログラムは以下です。
異なる構造体をまとめて、リテラルスライスで出力しようとしています。

GO

1package main 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7) 8 9//Command ENT 10type Command struct { 11 Command string `json:"command"` 12 Tables []Table `json:"table"` 13} 14 15//Table Data 16type Table1 struct { 17 TableName string `json:"table_name"` 18 Clientid int `json:"clientid"` 19 Server string `json:"server"` 20} 21 22type Table2 struct { 23 TableName string `json:"table_name"` 24 Clientid int `json:"clientid"` 25 TimeControl int `json:"time_control"` 26} 27 28type Table struct { 29 Table1 Table1 30 Table2 Table2 31} 32 33func main() { 34 BasicConfig := Table1{TableName: "basic", Clientid: 0, Server: "basic"} 35 ContentsFunc := Table2{TableName: "contents", Clientid: 0, TimeControl: 0} 36 jsonStr := Command{ 37 Command: "ENT", 38 Tables: []Table{ 39 { 40 BasicConfig, 41 ContentsFunc, 42 }, 43 }, 44 } 45 46 jsonBytes, err := json.Marshal(jsonStr) 47 if err != nil { 48 fmt.Println("JSON Marshal error:", err) 49 return 50 } 51 out := new(bytes.Buffer) 52 // プリフィックスなし、スペース4つでインデント 53 json.Indent(out, jsonBytes, "", " ") 54 fmt.Println(out.String()) 55} 56

よろしくおねがいします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

JSONに対応するオブジェクトでよく勘違いされるパターンのひとつなんですが、
似て異なるものを別の型として表現しようとすることです。
実際はフィールドがオミットされているだけで同じ型を使っているという解釈で済む場合が多々あります。

そもそもTableというアレイフィールドに
異なる型のオブジェクトを入れ込むような設計はかなり稀です。

JSONの各要素の型を設計をするときはできるだけ型を決めて
その「あるPath」に対する「値の型」は一定であるという設計がお勧めですし、
そうなっていないJSON設計は良くない設計だと思います。

今回の事例も以下のように一つのTable型で済みます。

https://play.golang.org/p/qj9DPdI7qmV

go

1package main 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7) 8 9type Command struct { 10 Command string `json:"command"` 11 Table []Table `json:"table"` 12} 13 14type Table struct { 15 TableName string `json:"table_name"` 16 Clientid int `json:"clientid"` 17 Server string `json:"server,omitempty"` 18 TimeControl string `json:"time_control,omitempty"` 19} 20 21func main() { 22 BasicConfig := Table{TableName: "basic", Clientid: 0, Server: "basic", TimeControl:""} 23 ContentsFunc := Table{TableName: "contents", Clientid: 0, Server:"", TimeControl: "0"} 24 jsonStr := Command{ 25 Command: "ENT", 26 Table: []Table{ 27 BasicConfig, 28 ContentsFunc, 29 }, 30 } 31 32 jsonBytes, err := json.Marshal(jsonStr) 33 if err != nil { 34 fmt.Println("JSON Marshal error:", err) 35 return 36 } 37 out := new(bytes.Buffer) 38 // プリフィックスなし、スペース4つでインデント 39 json.Indent(out, jsonBytes, "", " ") 40 fmt.Println(out.String()) 41}

投稿2020/06/29 07:39

編集2020/06/29 07:42
nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nobonobo

2020/06/29 07:53

ちなみに2つのオミットフィールドの「両方に有効な値がある」「両方がエンプティである」のはNGであるという場合のチェックの責任は「JSONデコード結果を受け取る側」または「JSONエンコードに値を渡す側」の責任です。
Gunjirk

2020/06/29 08:00

nobonoboさん、丁寧なご回答ありがとうございます。 無事に解決いたしました。 nobonoboさんのおっしゃる勘違いをしておりました。 もう少しGOを勉強していきます。 JSON設計に関しても見直していきます。 今後ともよろしくお願いします。
guest

0

nobonobo さんの回答のとおり、両方のsrtuctのフィールドをもつstructを用いて処理するのが良いと思います。

あえて、汎用的に何でも受け取るようにしたいのであれば、以下のように []interface{} で受けてしまうのも最終手段の方法としてはあるかな、と思います。

go

1//Command ENT 2type Command struct { 3 Command string `json:"command"` 4 Tables []interface{} `json:"table"` 5}

https://play.golang.org/p/ZVOxE5qHOnX

  • 出力結果
{ "command": "ENT", "table": [ { "table_name": "basic", "clientid": 0, "server": "basic" }, { "table_name": "contents", "clientid": 0, "time_control": 0 } ] }

投稿2020/06/29 07:59

d_tutuz

総合スコア730

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Gunjirk

2020/06/29 08:03

d_tutuzさん、引き続きご回答いただきありがとうございます。 interfaceも使えるのですね! 試してみたいと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問