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"} */} |