arrays - decoding nested json objects in go -
i found posts on how decoding json nested objects in go, tried apply answers problem, managed find partial solution.
my json file this:
{ "user":{ "gender":"male", "age":"21-30", "id":"80b1ea88-19d7-24e8-52cc-65cf6fb9b380" }, "trials":{ "0":{"index":0,"word":"word 1","time":3000,"keyboard":true,"train":true,"type":"a"}, "1":{"index":1,"word":"word 2","time":3000,"keyboard":true,"train":true,"type":"a"}, }, "answers":{ "training":[ {"ans":0,"rt":null,"gtans":"word 1","correct":0}, {"ans":0,"rt":null,"gtans":"word 2","correct":0} ], "test":[ {"ans":0,"rt":null,"gtans":true,"correct":0}, {"ans":0,"rt":null,"gtans":true,"correct":0} ] } }
basically need parse information inside , save them go structure. code below managed extract user information, looks complicated me , won't easy apply same thing "answers" fields contains 2 arrays more 100 entries each. here code i'm using now:
type userdetails struct { id string `json:"id"` age string `json:"age"` gender string `json:"gender"` } type jsonrawdata map[string]interface { } func getjsoncontent(r *http.request) ( userdetails) { defer r.body.close() jsonbody, err := ioutil.readall(r.body) var userdatacurr userdetails if err != nil { log.printf("couldn't read request body: %s", err) } else { var f jsonrawdata err := json.unmarshal(jsonbody, &f) if err != nil { log.printf("error unmashalling: %s", err) } else { user := f["user"].(map[string]interface{}) userdatacurr.id = user["id"].(string) userdatacurr.gender = user["gender"].(string) userdatacurr.age = user["age"].(string) } } return userdatacurr }
any suggestions? lot!
you're doing hard way using interface{}
, not taking advantage of encoding/json
gives you.
i'd (note assumed there error type of "gtans" field , made boolean, don't give enough information know "rt" field):
package main import ( "encoding/json" "fmt" "io" "log" "strconv" "strings" ) const input = `{ "user":{ "gender":"male", "age":"21-30", "id":"80b1ea88-19d7-24e8-52cc-65cf6fb9b380" }, "trials":{ "0":{"index":0,"word":"word 1","time":3000,"keyboard":true,"train":true,"type":"a"}, "1":{"index":1,"word":"word 2","time":3000,"keyboard":true,"train":true,"type":"a"} }, "answers":{ "training":[ {"ans":0,"rt":null,"gtans":true,"correct":0}, {"ans":0,"rt":null,"gtans":true,"correct":0} ], "test":[ {"ans":0,"rt":null,"gtans":true,"correct":0}, {"ans":0,"rt":null,"gtans":true,"correct":0} ] } }` type whatever struct { user struct { gender gender `json:"gender"` age range `json:"age"` id idstring `json:"id"` } `json:"user"` trials map[string]struct { index int `json:"index"` word string `json:"word"` time int // should time.duration? train bool `json:"train"` type string `json:"type"` } `json:"trials"` answers map[string][]struct { answer int `json:"ans"` rt json.rawmessage // ??? type gotanswer bool `json:"gtans"` correct int `json:"correct"` } `json:"answers"` } // using custom types show custom marshalling: type idstring string // todo custom unmarshal , format/error checking type gender int const ( male gender = iota female ) func (g *gender) unmarshaljson(b []byte) error { var s string err := json.unmarshal(b, &s) if err != nil { return err } switch strings.tolower(s) { case "male": *g = male case "female": *g = female default: return fmt.errorf("invalid gender %q", s) } return nil } func (g gender) marshaljson() ([]byte, error) { switch g { case male: return []byte(`"male"`), nil case female: return []byte(`"female"`), nil default: return nil, fmt.errorf("invalid gender %v", g) } } type range struct{ min, max int } func (r *range) unmarshaljson(b []byte) error { // xxx improved _, err := fmt.sscanf(string(b), `"%d-%d"`, &r.min, &r.max) return err } func (r range) marshaljson() ([]byte, error) { return []byte(fmt.sprintf(`"%d-%d"`, r.min, r.max)), nil // or: b := make([]byte, 0, 8) b = append(b, '"') b = strconv.appendint(b, int64(r.min), 10) b = append(b, '-') b = strconv.appendint(b, int64(r.max), 10) b = append(b, '"') return b, nil } func fromjson(r io.reader) (whatever, error) { var x whatever dec := json.newdecoder(r) err := dec.decode(&x) return x, err } func main() { // use http.get or whatever io.reader, // (e.g. response.body). // playground, substitute fixed string r := strings.newreader(input) // if had string or []byte: // var x whatever // err := json.unmarshal([]byte(input), &x) x, err := fromjson(r) if err != nil { log.fatal(err) } fmt.println(x) fmt.printf("%+v\n", x) b, err := json.marshalindent(x, "", " ") if err != nil { log.fatal(err) } fmt.printf("re-marshalled: %s\n", b) }
of course if want reuse sub-types pull them out of "whatever" type own named types.
also, note use of json.decoder
rather reading in data ahead of time. try , avoid use of ioutil.readall
unless need data @ once.
Comments
Post a Comment