Golangで構造体を定義せずにjsonを読み込んでみる
ふとした時にGolangでjsonを読み込む話になり
事前に構造体を定義しないでreflectで読み込んで云々・・・みたいな話になりました。
そう言えばGolangでreflectをまともに使ったことがないなあ、と思い
勉強がてらサンプルソースを作ってみました。
以下、サンプルソースとその機能について、備忘録替わりに書いておきます。
機能について
サポートされるログと検出されるフィールド - Amazon CloudWatch Logs
こちらにある CloudWatch のjson形式のログを読み込むことにしました。
最初に書いたようにjsonに対応する構造体は定義せず、reflectを使いjsonを読み込みます。
ネストした任意のjsonを読み込み、キー・値・型を取得する機能を想定しています。
サンプルプログラム
以下のようになりました。
package main import ( "encoding/json" "fmt" "io/ioutil" "log" "reflect" ) func doReflect(interfc interface{}) { r := reflect.ValueOf(interfc) if r.Kind() == reflect.Map { iter := r.MapRange() for iter.Next() { k := iter.Key() v := iter.Value() _, isStr := v.Interface().(string) _, isNum := v.Interface().(float64) if isStr || isNum { fmt.Printf("keys = %v, val = %v, type = %v\n", k, v, reflect.TypeOf(v.Interface())) } else { doReflect(v.Interface()) } } return } else if r.Kind() == reflect.Slice { for i := 0; i < r.Len(); i++ { doReflect(r.Index(i).Interface()) } } } func main() { bytes, err := ioutil.ReadFile("./sample.json") if err != nil { log.Fatal(err) } var contents interface{} err = json.Unmarshal(bytes, &contents) if err != nil { log.Fatal(err) } doReflect(contents) }
実行すると、jsonのキー・値・型が出力されるかと思います。
型は今回はstring、floatのみですが、jsonによっては型を増やすことも可能かと思います。