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

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

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

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

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Q&A

解決済

2回答

1966閲覧

Go言語で親の構造が同じで子の構造が違うjsonのパース

jgvkmea

総合スコア25

Go

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

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

0グッド

1クリップ

投稿2020/08/11 15:41

Go言語でコードを書いていてjsonを構造体にパースしようとしているのですが、うまい書き方がわからず困っています。

例えば下記のような2つのjsonを構造体にパースする場合についてです。

json

1{ 2 time: XXX, 3 result:{ 4 id: 1, 5 name: "name" 6 }, 7 status: XXX 8}

json

1{ 2 time: XXX, 3 result:{ 4 year: 2020, 5 month: 8, 6 day: 12 7 }, 8 status: XXX 9}

この場合、json の1階層目(?)は

  • time
  • result
  • status

で、フィールドは一致していて、result内が異なっています。

この場合パースするための構造体は、

go

1type hoge struct { 2 Time string 3 Result hogeResult{} 4 status int 5} 6 7type hogeResult struct { 8 id int 9 name string 10} 11 12type fuga struct { 13 Time string 14 Result fugaResult{} 15 status int 16} 17 18type fugaResult struct { 19 year int 20 month int 21 day int 22}

の4つを用意しなければなりませんか?
hogefugaの構造体をまとめる方法はありますか?

ちなみに、Resultの型をinterface{}にするのは試したのですが、
その後の処理でResult内のフィールドにアクセスできなかったので、この方法以外でお願いします。

ご回答よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

例えば、親の何らかの値によって子のJSONの構造が分かる場合、json.RawMessage としてデータを保持しておき、わかったタイミングで遅延して json.Unmarshal するのが一つの方法です。

go

1type myStruct struct { 2 Time time.Time `json:"time"` 3 Result json.RawMessage `json:"result"` 4 Status int `json:"status"` 5} 6 7type hogeResult struct { 8 ID int 9 Name string 10} 11 12type fugaResult struct { 13 Year int 14 Month int 15 Day int 16}

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


あるいは、両方のJSONをまとめて格納できるようにstructをマージする方法があります。ただし、値が格納されているかどうかは、json.Unmarshal 後のフィールドの値がゼロ値かどうかで判断する必要があります。

go

1type myStruct struct { 2 Time time.Time `json:"time"` 3 Result hogeStruct `json:"result"` 4 Status int `json:"status"` 5} 6 7type hogeStruct struct { 8 ID int `json:"ID"` 9 Name string `json:"name"` 10 Year int `json:"year"` 11 Month int `json:"month"` 12 Day int `json:"day"` 13}

https://play.golang.org/p/2pwRKv3DM_n

投稿2020/08/11 22:22

編集2020/08/11 22:22
d_tutuz

総合スコア730

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

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

0

僕も d_tutuz さんと同じ方法を選びます。メソッドを付けてユーザがどちらか取れる様にするのもアリかと思いました。

go

1package main 2 3import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "strings" 8) 9 10type Result map[string]interface{} 11 12type Data struct { 13 Time string `json:"time"` 14 Result json.RawMessage `json:"result"` 15 Status string `json:"status"` 16} 17 18type ResultA struct { 19 ID int `json:"id,omitempty"` 20 Name string `json:"name,omitempty"` 21} 22 23type ResultB struct { 24 Year int `json:"year"` 25 Month int `json:"month"` 26 Day int `json:"day"` 27} 28 29func (r *Data) ResultA() (*ResultA, error) { 30 var A ResultA 31 if err := json.Unmarshal(r.Result, &A); err != nil { 32 return nil, err 33 } 34 return &A, nil 35} 36 37func (r *Data) ResultB() (*ResultB, error) { 38 var B ResultB 39 if err := json.Unmarshal(r.Result, &B); err != nil { 40 return nil, err 41 } 42 return &B, nil 43} 44 45const j = ` 46{ 47 "time": "XXX", 48 "result":{ 49 "id": 1, 50 "name": "name" 51 }, 52 "status": "XXX" 53} 54` 55 56func main() { 57 var v Data 58 err := json.NewDecoder(strings.NewReader(j)).Decode(&v) 59 if err != nil { 60 log.Fatal(err) 61 } 62 a, _ := v.ResultA() 63 fmt.Println(a) 64 b, _ := v.ResultB() 65 fmt.Println(b) 66}

https://play.golang.org/p/0z8fFhViXJ1

投稿2020/08/12 02:13

編集2020/08/12 03:13
mattn

総合スコア5030

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問