golangでstructにマッピング前にJSONの特定のプロパティの値を確認したい


上記をやりたいことがたまにある.

具体的に言うと

type DataV1 struct {
	Version string `json:"version"` // value: "v1"
	X       string `json:"x"`       // value: "123.4"
	Y       string `json:"y"`       // value: "123.4"
}

type DataV2 struct {
	Version string `json:"version"` // value: "v2"
	X       int64  `json:"x"`       // value: 123.4
	Y       int64  `json:"y"`       // value: 123.4
}

DataV1のX, Yはstring型だが. 次バージョンのDataV2ではint64になっている.

中の構造体がバージョンごとに変わっているために振り分けをしたい!

そういう時にgithub.com/antonholmquist/jasonが役に立ちました.

極端なコードで恐縮ですが

package main

import "github.com/antonholmquist/jason"

type DataV1 struct {
	Version string `json:"version"` // value: "v1"
	X       string `json:"x"`       // value: "123.4"
	Y       string `json:"y"`       // value: "123.4"
}

type DataV2 struct {
	Version string `json:"version"` // value: "v2"
	X       int64  `json:"x"`       // value: 123.4
	Y       int64  `json:"y"`       // value: 123.4
}

var jsonDataString = "..."

func main() {
	obj, err := jason.NewObjectFromBytes([]byte(jsonDataString))
	if err != nil {
		panic(err)
	}

	version, err := obj.GetString("version")
	if err != nil {
		panic(err)
	}

	if version == "v1" {
		x, err := obj.GetString("x")
		if err != nil {
			panic(err)
		}

		y, err := obj.GetString("y")
		if err != nil {
			panic(err)
		}

		data := DataV1{
			Version: "v1",
			X:       x,
			Y:       y,
		}

		// do something...

	} else if version == "v2" {
		x, err := obj.GetFloat64("x")
		if err != nil {
			panic(err)
		}

		y, err := obj.GetFloat64("y")
		if err != nil {
			panic(err)
		}

		data := DataV2{
			Version: "v2",
			X:       x,
			Y:       y,
		}

		// do something...

	}
}

こんなかんじにいけます.

ただJSONが複雑な場合いちいち値を取得して自前でstructにマッピングしていくのが本当にだるくなるので, そういう場合は正規表現などでチェックするほうがいいかもしれません. (再度デシリアライズするコスト無しに簡単にリマッピングできる手段がほしい…

マッピング前に処理したいっていうとき以外でもさくっと値を取りたいってケースでも簡単に行えて便利ですね.

あとはネストされた値も簡単に取れますし何かと便利なのではないでしょうか.