// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Marshalling and unmarshalling of // JSON data into Go structs using reflection. package json import ( "reflect"; "strings"; ) type _StructBuilder struct { val reflect.Value } var nobuilder *_StructBuilder func isfloat(v reflect.Value) bool { switch v := v.(type) { case *reflect.FloatValue: return true; case *reflect.Float32Value: return true; case *reflect.Float64Value: return true; } return false; } func setfloat(v reflect.Value, f float64) { switch v := v.(type) { case *reflect.FloatValue: v.Set(float(f)); case *reflect.Float32Value: v.Set(float32(f)); case *reflect.Float64Value: v.Set(float64(f)); } } func setint(v reflect.Value, i int64) { switch v := v.(type) { case *reflect.IntValue: v.Set(int(i)); case *reflect.Int8Value: v.Set(int8(i)); case *reflect.Int16Value: v.Set(int16(i)); case *reflect.Int32Value: v.Set(int32(i)); case *reflect.Int64Value: v.Set(int64(i)); case *reflect.UintValue: v.Set(uint(i)); case *reflect.Uint8Value: v.Set(uint8(i)); case *reflect.Uint16Value: v.Set(uint16(i)); case *reflect.Uint32Value: v.Set(uint32(i)); case *reflect.Uint64Value: v.Set(uint64(i)); } } func (b *_StructBuilder) Int64(i int64) { if b == nil { return } v := b.val; if isfloat(v) { setfloat(v, float64(i)); } else { setint(v, i); } } func (b *_StructBuilder) Uint64(i uint64) { if b == nil { return } v := b.val; if isfloat(v) { setfloat(v, float64(i)); } else { setint(v, int64(i)); } } func (b *_StructBuilder) Float64(f float64) { if b == nil { return } v := b.val; if isfloat(v) { setfloat(v, f); } else { setint(v, int64(f)); } } func (b *_StructBuilder) Null() { } func (b *_StructBuilder) String(s string) { if b == nil { return } if v, ok := b.val.(*reflect.StringValue); ok { v.Set(s); } } func (b *_StructBuilder) Bool(tf bool) { if b == nil { return } if v, ok := b.val.(*reflect.BoolValue); ok { v.Set(tf); } } func (b *_StructBuilder) Array() { if b == nil { return } if v, ok := b.val.(*reflect.SliceValue); ok { if v.IsNil() { v.Set(reflect.MakeSlice(v.Type().(*reflect.SliceType), 0, 8)); } } } func (b *_StructBuilder) Elem(i int) Builder { if b == nil || i < 0 { return nobuilder } switch v := b.val.(type) { case *reflect.ArrayValue: if i < v.Len() { return &_StructBuilder{ v.Elem(i) } } case *reflect.SliceValue: if i > v.Cap() { n := v.Cap(); if n < 8 { n = 8 } for n <= i { n *= 2 } nv := reflect.MakeSlice(v.Type().(*reflect.SliceType), v.Len(), n); reflect.ArrayCopy(nv, v); v.Set(nv); } if v.Len() <= i && i < v.Cap() { v.SetLen(i+1); } if i < v.Len() { return &_StructBuilder{ v.Elem(i) } } } return nobuilder; } func (b *_StructBuilder) Map() { if b == nil { return } if v, ok := b.val.(*reflect.PtrValue); ok { if v.IsNil() { v.PointTo(reflect.MakeZero(v.Type().(*reflect.PtrType).Elem())) } } } func (b *_StructBuilder) Key(k string) Builder { if b == nil { return nobuilder } if v, ok := reflect.Indirect(b.val).(*reflect.StructValue); ok { t := v.Type().(*reflect.StructType); if field, ok := t.FieldByName(k); ok { return &_StructBuilder{ v.FieldByIndex(field.Index) } } // Again, case-insensitive. for i := 0; i < t.NumField(); i++ { if strings.LowerASCII(t.Field(i).Name) == k { return &_StructBuilder{ v.Field(i) } } } } return nobuilder } // Unmarshal parses the JSON syntax string s and fills in // an arbitrary struct or array pointed at by val. // It uses the reflection library to assign to fields // and arrays embedded in val. Well-formed data that does not fit // into the struct is discarded. // // For example, given the following definitions: // // type Email struct { // where string; // addr string; // } // // type Result struct { // name string; // phone string; // emails []Email // } // // var r = Result{ "name", "phone", nil } // // unmarshalling the JSON syntax string // // { // "email": [ // { // "where": "home", // "addr": "gre@example.com" // }, // { // "where": "work", // "addr": "gre@work.com" // } // ], // "name": "Grace R. Emlin", // "address": "123 Main Street" // } // // via Unmarshal(s, &r) is equivalent to assigning // // r = Result{ // "Grace R. Emlin", // name // "phone", // no phone given // []Email{ // Email{ "home", "gre@example.com" }, // Email{ "work", "gre@work.com" } // } // } // // Note that the field r.phone has not been modified and // that the JSON field "address" was discarded. // // On success, Unmarshal returns with ok set to true. // On a syntax error, it returns with ok set to false and errtok // set to the offending token. func Unmarshal(s string, val interface{}) (ok bool, errtok string) { var errindx int; var val1 interface{}; b := &_StructBuilder{ reflect.NewValue(val) }; ok, errindx, errtok = Parse(s, b); if !ok { return false, errtok } return true, "" }