diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/json/generic.go | 45 | ||||
-rw-r--r-- | src/lib/json/parse.go | 24 | ||||
-rw-r--r-- | src/lib/json/struct.go | 55 |
3 files changed, 113 insertions, 11 deletions
diff --git a/src/lib/json/generic.go b/src/lib/json/generic.go index f42d41170..7ce315765 100644 --- a/src/lib/json/generic.go +++ b/src/lib/json/generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Generic JSON representation. +// Generic representation of JSON objects. package json @@ -15,6 +15,7 @@ import ( "vector"; ) +// Integers identifying the data type in the Json interface. const ( StringKind = iota; NumberKind; @@ -24,16 +25,23 @@ const ( NullKind; ) +// The Json interface is implemented by all JSON objects. type Json interface { - Kind() int; - String() string; - Number() float64; - Bool() bool; - Get(s string) Json; - Elem(i int) Json; - Len() int; + 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) } +// 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" @@ -45,7 +53,10 @@ func JsonToString(j Json) 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 } @@ -128,6 +139,14 @@ func (j *_Map) String() string { 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; @@ -154,6 +173,7 @@ func Walk(j Json, path string) Json { return j } +// Equal returns whether a and b are indistinguishable JSON objects. func Equal(a, b Json) bool { switch { case a == nil && b == nil: @@ -201,7 +221,7 @@ func Equal(a, b Json) bool { } -// Parse builder for Json objects. +// Parse builder for JSON objects. type _JsonBuilder struct { // either writing to *ptr @@ -290,6 +310,11 @@ func (b *_JsonBuilder) Key(k string) Builder { 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; @@ -301,3 +326,5 @@ func StringToJson(s string) (json Json, ok bool, errtok string) { } return j, true, "" } + +// BUG(rsc): StringToJson should return an *os.Error instead of a bool. diff --git a/src/lib/json/parse.go b/src/lib/json/parse.go index e9c4a31b5..1069e1183 100644 --- a/src/lib/json/parse.go +++ b/src/lib/json/parse.go @@ -5,6 +5,9 @@ // JSON (JavaScript Object Notation) parser. // See http://www.json.org/ +// The json package implements a simple parser and +// representation for JSON (JavaScript Object Notation), +// as defined at http://www.json.org/. package json import ( @@ -43,6 +46,9 @@ func _UnHex(p string, r, l int) (v int, ok bool) { return v, true; } +// Unquote unquotes the JSON-quoted string s, +// returning a raw string t. If s is not a valid +// JSON-quoted string, Unquote returns with ok set to false. func Unquote(s string) (t string, ok bool) { if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { return @@ -116,6 +122,8 @@ func Unquote(s string) (t string, ok bool) { return string(b[0:w]), true } +// Quote quotes the raw string s using JSON syntax, +// so that Unquote(Quote(s)) = s, true. func Quote(s string) string { chr := make([]byte, utf8.UTFMax); chr0 := chr[0:1]; @@ -271,6 +279,12 @@ func (t *_Lexer) Next() { type _Value interface {} +// BUG(rsc): The json Builder interface needs to be +// reconciled with the xml Builder interface. + +// A Builder is an interface implemented by clients and passed +// to the JSON parser. It gives clients full control over the +// eventual representation returned by the parser. type Builder interface { // Set value Int64(i int64); @@ -385,11 +399,17 @@ Switch: return ok; } -func Parse(s string, build Builder) (ok bool, errindx int, errtok string) { +// Parse parses the JSON syntax string s and makes calls to +// the builder to construct a parsed representation. +// On success, it returns with ok set to true. +// On error, it returns with ok set to false, errindx set +// to the byte index in s where a syntax error occurred, +// and errtok set to the offending token. +func Parse(s string, builder Builder) (ok bool, errindx int, errtok string) { lex := new(_Lexer); lex.s = s; lex.Next(); - if parse(lex, build) { + if parse(lex, builder) { if lex.kind == 0 { // EOF return true, 0, "" } diff --git a/src/lib/json/struct.go b/src/lib/json/struct.go index 82e0a80a7..cfba2ce6d 100644 --- a/src/lib/json/struct.go +++ b/src/lib/json/struct.go @@ -202,6 +202,61 @@ func (b *_StructBuilder) Key(k string) Builder { 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{}; |