Golangで構造体を使ったJSON操作で出来ることを調べてみた
西田@大阪です。
Golangでできる構造体を使ったJSON操作を調べてみました。
struct tags
Golangでは structタグでJSONの処理をある程度制御することができます。
記述例
1 2 3 4 | type Sample struct { // json:<マッピングするJSONオブジェクトのフィールド名>,<オプション> という形式で記述します FieldName string `json: "field_name,string" ` } |
用意されているオプションは以下の通りです。
タグ | Marshal(JSON出力)時 | Unmarshal(JSONパース)時 | 例 |
---|---|---|---|
omitempty | 0値(空文字、0、nil等)であればフィールドを出力しない | 0値であれば無視される | json:"field,omitempty" |
- | 出力しない | 無視される | json:"-" |
string | 出力時に Quote される |
Quote されていても型に合わせて変換する。Quote されてないとエラー |
json:"field,string" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | type JSONSample struct { Field string `json: "field" ` Omit string `json: "-" ` OmitEmpty string `json: "omit_empty,omitempty" ` Num int `json: "num,string" ` } func main() { sample := JSONSample{ Field: "field" , Omit: "omit" , OmitEmpty: "" , Num: 1, } bytes, _ := json.Marshal(&sample) fmt.Println(string(bytes)) /* -- output { "field": "field", "num":"1" } - omitは省略されています - omit_emptyは値がないので、JSONではフィールドごと省略されてます - numは Golangではint型ですが、JSONではstructタグでstringが指定されているのでQuoteされて出力されています */ j := ` { "field" : "field" , "omit" : "omit" , "omit_empty" : "a" , "num" : "123" } ` var decoded JSONSample json.Unmarshal([]byte(j), &decoded) fmt.Printf( "%v\n" , decoded) /* -- output {field a 123} - omitは値があってもけされています - emit_emptyは値があるので、構造体に値として設定されています - numはJSONでは文字列ですが、structタグで設定 string を設定されているので構造体の型であるintに変換されてます */ } |
カスタム
structタグのみでできない処理は MarshalJSON
UnmarshalJSON
関数を定義しカスタムすることが可能です。
例えば、time.Time
型は RFC3339(2006-01-02T15:04:05Z07:00) しか time.Time
型に変換できないですが、MarshalJSON
UnmarshalJSON
メソッドを定義することによって、別の日付のフォーマットでも取り扱うことが可能です。
下記は 2017/09/05
のようなフォーマットで日付を扱いたい場合の例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 新しい構造体を宣言します。元の構造体と同じように扱いたいので embedded してます type MyTime struct { *time.Time } // Unmarshal時の動作を定義します func (mt *MyTime) UnmarshalJSON(data []byte) error { // 要素がそのまま渡ってくるので "(ダブルクォート)でQuoteされてます t, err := time.Parse( "\"2006/01/02\"" , string(data)) *mt = MyTime{&t} return err } // Marshal時の動作を定義します func (mt MyTime) MarshalJSON() ([]byte, error) { return json.Marshal(mt.Format( "2006/01/02" )) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | type JSONSample struct { TimeAt MyTime `json: "time_at" ` } func main() { j := ` { "time_at" : "2017/09/12" } ` var decoded JSONSample json.Unmarshal([]byte(j), &decoded) fmt.Printf( "%v\n" , decoded) /* -- output {2017-09-12 00:00:00 +0000 UTC} */ j2, _ := json.Marshal(decoded) fmt.Printf( "%v" , string(j2)) /* -- output {"time_at":"2017/09/12"} */ } |