| // 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. |
| |
| // Generic representation of JSON objects. |
| |
| package json |
| |
| import ( |
| "container/vector"; |
| "fmt"; |
| "json"; |
| "math"; |
| "strconv"; |
| "strings"; |
| ) |
| |
| // Integers identifying the data type in the Json interface. |
| const ( |
| StringKind = iota; |
| NumberKind; |
| MapKind; // JSON term is "Object", but in Go, it's a map |
| ArrayKind; |
| BoolKind; |
| NullKind; |
| ) |
| |
| // The Json interface is implemented by all JSON objects. |
| type Json interface { |
| Kind() int; // StringKind, NumberKind, etc. |
| String() string; // a string form (any kind) |
| Number() float64; // numeric form (NumberKind) |
| Bool() bool; // boolean (BoolKind) |
| Get(s string) Json; // field lookup (MapKind) |
| Elem(i int) Json; // element lookup (ArrayKind) |
| Len() int; // length (ArrayKind, MapKind) |
| } |
| |
| // JsonToString returns the textual JSON syntax representation |
| // for the JSON object j. |
| // |
| // JsonToString differs from j.String() in the handling |
| // of string objects. If j represents the string abc, |
| // j.String() == `abc`, but JsonToString(j) == `"abc"`. |
| func JsonToString(j Json) string { |
| if j == nil { |
| return "null" |
| } |
| if j.Kind() == StringKind { |
| return Quote(j.String()) |
| } |
| return j.String() |
| } |
| |
| type _Null struct { } |
| |
| // Null is the JSON object representing the null data object. |
| var Null Json = &_Null{} |
| |
| func (*_Null) Kind() int { return NullKind } |
| func (*_Null) String() string { return "null" } |
| func (*_Null) Number() float64 { return 0 } |
| func (*_Null) Bool() bool { return false } |
| func (*_Null) Get(s string) Json { return Null } |
| func (*_Null) Elem(int) Json { return Null } |
| func (*_Null) Len() int { return 0 } |
| |
| type _String struct { s string; _Null } |
| func (j *_String) Kind() int { return StringKind } |
| func (j *_String) String() string { return j.s } |
| |
| type _Number struct { f float64; _Null } |
| func (j *_Number) Kind() int { return NumberKind } |
| func (j *_Number) Number() float64 { return j.f } |
| func (j *_Number) String() string { |
| if math.Floor(j.f) == j.f { |
| return fmt.Sprintf("%.0f", j.f); |
| } |
| return fmt.Sprintf("%g", j.f); |
| } |
| |
| type _Array struct { a *vector.Vector; _Null } |
| func (j *_Array) Kind() int { return ArrayKind } |
| func (j *_Array) Len() int { return j.a.Len() } |
| func (j *_Array) Elem(i int) Json { |
| if i < 0 || i >= j.a.Len() { |
| return Null |
| } |
| return j.a.At(i).(Json) |
| } |
| func (j *_Array) String() string { |
| s := "["; |
| for i := 0; i < j.a.Len(); i++ { |
| if i > 0 { |
| s += ","; |
| } |
| s += JsonToString(j.a.At(i).(Json)); |
| } |
| s += "]"; |
| return s; |
| } |
| |
| type _Bool struct { b bool; _Null } |
| func (j *_Bool) Kind() int { return BoolKind } |
| func (j *_Bool) Bool() bool { return j.b } |
| func (j *_Bool) String() string { |
| if j.b { |
| return "true" |
| } |
| return "false" |
| } |
| |
| type _Map struct { m map[string]Json; _Null } |
| func (j *_Map) Kind() int { return MapKind } |
| func (j *_Map) Len() int { return len(j.m) } |
| func (j *_Map) Get(s string) Json { |
| if j.m == nil { |
| return Null |
| } |
| v, ok := j.m[s]; |
| if !ok { |
| return Null |
| } |
| return v; |
| } |
| func (j *_Map) String() string { |
| s := "{"; |
| first := true; |
| for k,v := range j.m { |
| if first { |
| first = false; |
| } else { |
| s += ","; |
| } |
| s += Quote(k); |
| s += ":"; |
| s += JsonToString(v); |
| } |
| s += "}"; |
| return s; |
| } |
| |
| // Walk evaluates path relative to the JSON object j. |
| // Path is taken as a sequence of slash-separated field names |
| // or numbers that can be used to index into JSON map and |
| // array objects. |
| // |
| // For example, if j is the JSON object for |
| // {"abc": [true, false]}, then Walk(j, "abc/1") returns the |
| // JSON object for true. |
| func Walk(j Json, path string) Json { |
| for len(path) > 0 { |
| var elem string; |
| if i := strings.Index(path, "/"); i >= 0 { |
| elem = path[0:i]; |
| path = path[i+1:len(path)]; |
| } else { |
| elem = path; |
| path = ""; |
| } |
| switch j.Kind() { |
| case ArrayKind: |
| indx, err := strconv.Atoi(elem); |
| if err != nil { |
| return Null |
| } |
| j = j.Elem(indx); |
| case MapKind: |
| j = j.Get(elem); |
| default: |
| return Null |
| } |
| } |
| return j |
| } |
| |
| // Equal returns whether a and b are indistinguishable JSON objects. |
| func Equal(a, b Json) bool { |
| switch { |
| case a == nil && b == nil: |
| return true; |
| case a == nil || b == nil: |
| return false; |
| case a.Kind() != b.Kind(): |
| return false; |
| } |
| |
| switch a.Kind() { |
| case NullKind: |
| return true; |
| case StringKind: |
| return a.String() == b.String(); |
| case NumberKind: |
| return a.Number() == b.Number(); |
| case BoolKind: |
| return a.Bool() == b.Bool(); |
| case ArrayKind: |
| if a.Len() != b.Len() { |
| return false; |
| } |
| for i := 0; i < a.Len(); i++ { |
| if !Equal(a.Elem(i), b.Elem(i)) { |
| return false; |
| } |
| } |
| return true; |
| case MapKind: |
| m := a.(*_Map).m; |
| if len(m) != len(b.(*_Map).m) { |
| return false; |
| } |
| for k,v := range m { |
| if !Equal(v, b.Get(k)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // invalid kind |
| return false; |
| } |
| |
| |
| // Parse builder for JSON objects. |
| |
| type _JsonBuilder struct { |
| // either writing to *ptr |
| ptr *Json; |
| |
| // or to a[i] (can't set ptr = &a[i]) |
| a *vector.Vector; |
| i int; |
| |
| // or to m[k] (can't set ptr = &m[k]) |
| m map[string] Json; |
| k string; |
| } |
| |
| func (b *_JsonBuilder) Put(j Json) { |
| switch { |
| case b.ptr != nil: |
| *b.ptr = j; |
| case b.a != nil: |
| b.a.Set(b.i, j); |
| case b.m != nil: |
| b.m[b.k] = j; |
| } |
| } |
| |
| func (b *_JsonBuilder) Get() Json { |
| switch { |
| case b.ptr != nil: |
| return *b.ptr; |
| case b.a != nil: |
| return b.a.At(b.i).(Json); |
| case b.m != nil: |
| return b.m[b.k]; |
| } |
| return nil |
| } |
| |
| func (b *_JsonBuilder) Float64(f float64) { |
| b.Put(&_Number{f, _Null{}}) |
| } |
| |
| func (b *_JsonBuilder) Int64(i int64) { |
| b.Float64(float64(i)) |
| } |
| |
| func (b *_JsonBuilder) Uint64(i uint64) { |
| b.Float64(float64(i)) |
| } |
| |
| func (b *_JsonBuilder) Bool(tf bool) { |
| b.Put(&_Bool{tf, _Null{}}) |
| } |
| |
| func (b *_JsonBuilder) Null() { |
| b.Put(Null) |
| } |
| |
| func (b *_JsonBuilder) String(s string) { |
| b.Put(&_String{s, _Null{}}) |
| } |
| |
| |
| func (b *_JsonBuilder) Array() { |
| b.Put(&_Array{vector.New(0), _Null{}}) |
| } |
| |
| func (b *_JsonBuilder) Map() { |
| b.Put(&_Map{make(map[string]Json), _Null{}}) |
| } |
| |
| func (b *_JsonBuilder) Elem(i int) Builder { |
| bb := new(_JsonBuilder); |
| bb.a = b.Get().(*_Array).a; |
| bb.i = i; |
| for i >= bb.a.Len() { |
| bb.a.Push(Null) |
| } |
| return bb |
| } |
| |
| func (b *_JsonBuilder) Key(k string) Builder { |
| bb := new(_JsonBuilder); |
| bb.m = b.Get().(*_Map).m; |
| bb.k = k; |
| bb.m[k] = Null; |
| return bb |
| } |
| |
| // StringToJson parses the string s as a JSON-syntax string |
| // and returns the generic JSON object representation. |
| // On success, StringToJson returns with ok set to true and errtok empty. |
| // If StringToJson encounters a syntax error, it returns with |
| // ok set to false and errtok set to a fragment of the offending syntax. |
| func StringToJson(s string) (json Json, ok bool, errtok string) { |
| var errindx int; |
| var j Json; |
| b := new(_JsonBuilder); |
| b.ptr = &j; |
| ok, errindx, errtok = Parse(s, b); |
| if !ok { |
| return nil, false, errtok |
| } |
| return j, true, "" |
| } |
| |
| // BUG(rsc): StringToJson should return an os.Error instead of a bool. |