Go言語(golang) JSON Marshal, Unmarshal, NewDecoder, NewEncoder の使い方
Go言語での JSON のパース/変換 Marshal, Unmarshal, NewDecoder, NewEncoder の使い方。
構造体のタグの指定方法については Go言語の構造体とJSON
に書きましたのでそちらをどうぞ。
ドキュメント
目次
- Go言語のデータ型(struct,map,slice) から JSON に変換する - Marshal
- JSON から Go言語のデータ型に変換する - Unmarshal
- Go言語のデータ型から JSON に変換する - NewEncoder
- JSON から Go言語のデータ型に変換する - NewDecoder
- トークン - NewDecoder - Token
- その他の関数
- エラーの判別
Go言語のデータ型(struct,map,slice) から JSON に変換する - Marshal
package main import ( "encoding/json" "fmt" ) func main() { m := map[string]interface{}{ "name": "Tanaka", "age": 30, } data, err := json.Marshal(m) if err != nil { fmt.Println(err) return } fmt.Println(string(data)) // {"age":30,"name":"Tanaka"} }
インデントをつける - MarshalIndent
package main import ( "encoding/json" "fmt" "strings" ) func main() { m := map[string]interface{}{ "name": "Tanaka", "age": 30, } data, err := json.MarshalIndent(m, "", strings.Repeat(" ", 2)) if err != nil { fmt.Println(err) return } fmt.Println(string(data)) // { // "age": 30, // "name": "Tanaka" // } }
JSON から Go言語のデータ型に変換する - Unmarshal
package main import ( "encoding/json" "fmt" ) func main() { data := `{ "name": "Tanaka", "age": 30 }` var m map[string]interface{} err := json.Unmarshal([]byte(data), &m) if err != nil { fmt.Println(err) return } fmt.Printf("%v\n", m) // map[name:Tanaka age:30] }
Go言語のデータ型から JSON に変換する - NewEncoder
Encoder を使えば *os.File
を引数にして書き出せる
package main import ( "encoding/json" "fmt" "os" "strings" ) func main() { m := map[string]interface{}{ "name": "Tanaka", "age": 30, "html": "<p>hello</p>", } fp, err := os.OpenFile("data.json", os.O_CREATE|os.O_WRONLY, 0664) if err != nil { fmt.Println(err) return } defer fp.Close() e := json.NewEncoder(fp) // HTML をエスケープするかどうか。たぶんデフォルトで true e.SetEscapeHTML(true) // インデントする。第一引数の prefix は何に使うんだろ?不明です e.SetIndent("", strings.Repeat(" ", 2)) if err := e.Encode(m); err != nil { fmt.Println(err) return } // { // "age": 30, // "html": "\u003cp\u003ehello\u003c/p\u003e", // "name": "Tanaka" // } }
JSON から Go言語のデータ型に変換する - NewDecoder
Decoder を使えば *os.File
を引数にできるので、
ioutil.ReadFile などを使ってファイルの中身をすべて読み出す必要がない
package main import ( "encoding/json" "fmt" "io" "strings" ) func main() { data := `{ "name": "Tanaka", "age": 30 }` var user struct { Name string `json:"name"` Age int `json:"age"` } // ファイルから読み込む場合は *os.File を指定する d := json.NewDecoder(strings.NewReader(data)) // 構造体の場合に、JSONのキー名がその構造体に無い場合はエラーにする strict モード // yaml.v2 と違って名前の重複は許されるようです。 d.DisallowUnknownFields() // エラーの場合 json: unknown field "JSONのフィールド名" if err := d.Decode(&user); err != nil && err != io.EOF { fmt.Println(err) return } fmt.Println(user) // {Tanaka 30} }
トークン - NewDecoder - Token
package main import ( "encoding/json" "fmt" "io" "strings" ) func main() { data := `{ "name": "Tanaka", "age": 30, "score": [10, 20, 30] }` d := json.NewDecoder(strings.NewReader(data)) for { t, err := d.Token() if err == io.EOF { break } if err != nil { fmt.Println(err) break } switch t.(type) { case json.Delim: // type が Delim `{}` とか `[]` fmt.Printf("%-11T: %v", t, t) default: // 続きがあるかどうかを真偽値で返す if d.More() { fmt.Printf("%-11T: %-8v < 続く", t, t) } else { fmt.Printf("%-11T: %-8v < 終わり", t, t) } } fmt.Printf("\n") } // 実行結果 // json.Delim : { // string : name < 続く // string : Tanaka < 続く // string : age < 続く // float64 : 30 < 続く // string : score < 続く // json.Delim : [ // float64 : 10 < 続く // float64 : 20 < 続く // float64 : 30 < 終わり // json.Delim : ] // json.Delim : } }
その他の関数
package main import ( "bytes" "encoding/json" "fmt" ) func main() { { // インデントを取り除く - Compact data := `{ "name": "Tanaka", "age": 30 }` var b bytes.Buffer err := json.Compact(&b, []byte(data)) if err != nil { fmt.Println(err) return } fmt.Println(b.String()) // {"name": "Tanaka", "age": 30} } { // HTML をエスケープする - HTMLEscape data := `["<p>hello</p>"]` var b bytes.Buffer json.HTMLEscape(&b, []byte(data)) fmt.Println(b.String()) // ["\u003cp\u003ehello\u003c/p\u003e"] } { // JSON文字列にインデントをつける - Indent data := `{"name": "Tanaka", "age": 30}` var b bytes.Buffer err := json.Indent(&b, []byte(data), "", " ") if err != nil { fmt.Println(err) return } fmt.Println(b.String()) // { // "name": "Tanaka", // "age": 30 // } } { // JSONとして有効な文字列かどうか確認する - Valid data := `{"name": "Tanaka", "age": 30}` ok := json.Valid([]byte(data)) if !ok { fmt.Println("Invalid as string of JSON") } } }
エラーの判別
package main import ( "encoding/json" "fmt" ) func main() { // エラーの種類を確認 if err != nil { switch err.(type) { case *json.SyntaxError: fmt.Printf("SyntaxError: %v\n", err) case *json.InvalidUTF8Error: // Windows で使えそう fmt.Printf("InvalidUTF8Error: %v\n", err) case *json.InvalidUnmarshalError: fmt.Printf("InvalidUnmarshalError: %v\n", err) case *json.UnmarshalFieldError: fmt.Printf("UnmarshalFieldError: %v\n", err) case *json.UnmarshalTypeError: fmt.Printf("UnmarshalTypeError: %v\n", err) case *json.MarshalerError: fmt.Printf("MarshalerError: %v\n", err) case *json.UnsupportedTypeError: fmt.Printf("UnsupportedTypeError: %v\n", err) case *json.UnsupportedValueError: fmt.Printf("UnsupportedValueError: %v\n", err) } } }