この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
西田@大阪です。
Golangでできる構造体を使ったJSON操作を調べてみました。
struct tags
Golangでは structタグでJSONの処理をある程度制御することができます。
記述例
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" |
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
のようなフォーマットで日付を扱いたい場合の例です。
// 新しい構造体を宣言します。元の構造体と同じように扱いたいので 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"))
}
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"}
*/
}