ソースコードから理解する技術-UnderSourceCode

手を動かす(プログラムを組む)ことで技術を理解するブログ

Golangで構造体を定義せずにjsonを読み込んでみる

ふとした時にGolangjsonを読み込む話になり
事前に構造体を定義しないでreflectで読み込んで云々・・・みたいな話になりました。

そう言えばGolangでreflectをまともに使ったことがないなあ、と思い
勉強がてらサンプルソースを作ってみました。

以下、サンプルソースとその機能について、備忘録替わりに書いておきます。

機能について

サポートされるログと検出されるフィールド - Amazon CloudWatch Logs

こちらにある CloudWatch のjson形式のログを読み込むことにしました。
最初に書いたようにjsonに対応する構造体は定義せず、reflectを使いjsonを読み込みます。
ネストした任意のjsonを読み込み、キー・値・型を取得する機能を想定しています。

実行には上記のjsonを「sample.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によっては型を増やすことも可能かと思います。