diff options
author | Russ Cox <rsc@golang.org> | 2008-12-11 12:25:58 -0800 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2008-12-11 12:25:58 -0800 |
commit | 8708b6b3e44bfd0da24095db8c4c49b425405158 (patch) | |
tree | e1ced2b2e9d92ddbcd1e7b6c9f53b57c529d0efc /src/lib/json/generic.go | |
parent | cfa051116c97dc97e02fcdde9887c2e455dead81 (diff) | |
download | golang-8708b6b3e44bfd0da24095db8c4c49b425405158.tar.gz |
add JSON library
R=r
DELTA=1127 (1127 added, 0 deleted, 0 changed)
OCL=20975
CL=20983
Diffstat (limited to 'src/lib/json/generic.go')
-rw-r--r-- | src/lib/json/generic.go | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/src/lib/json/generic.go b/src/lib/json/generic.go new file mode 100644 index 000000000..e5e76bf59 --- /dev/null +++ b/src/lib/json/generic.go @@ -0,0 +1,303 @@ +// 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 JSON representation. + +package json + +import ( + "array"; + "fmt"; + "math"; + "json"; + "strconv"; + "strings"; +) + +export const ( + StringKind = iota; + NumberKind; + MapKind; // JSON term is "Object", but in Go, it's a map + ArrayKind; + BoolKind; + NullKind; +) + +export type Json interface { + Kind() int; + String() string; + Number() float64; + Bool() bool; + Get(s string) Json; + Elem(i int) Json; + Len() int; +} + +export func JsonToString(j Json) string { + if j == nil { + return "null" + } + if j.Kind() == StringKind { + return Quote(j.String()) + } + return j.String() +} + +type Null struct { } +export 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 *array.Array; 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) +} +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) 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; +} + +export 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 +} + +export 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 *array.Array; + 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); + 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{array.New(0), Null{}}) +} + +func (b *JsonBuilder) Map() { + b.Put(&Map{new(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 +} + +export 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, "" +} |