Commit bccc3370 authored by Adam Langley's avatar Adam Langley

json: allow one to unmarshal a top-level JSON array.

Fixies issue 114.

R=rsc
CC=golang-dev
https://golang.org/cl/154121
parent e7b8f5fa
...@@ -224,7 +224,7 @@ func (b *structBuilder) Key(k string) Builder { ...@@ -224,7 +224,7 @@ func (b *structBuilder) Key(k string) Builder {
} }
// Unmarshal parses the JSON syntax string s and fills in // Unmarshal parses the JSON syntax string s and fills in
// an arbitrary struct or array pointed at by val. // an arbitrary struct or slice pointed at by val.
// It uses the reflect package to assign to fields // It uses the reflect package to assign to fields
// and arrays embedded in val. Well-formed data that does not fit // and arrays embedded in val. Well-formed data that does not fit
// into the struct is discarded. // into the struct is discarded.
...@@ -279,11 +279,27 @@ func (b *structBuilder) Key(k string) Builder { ...@@ -279,11 +279,27 @@ func (b *structBuilder) Key(k string) Builder {
// assign to upper case fields. Unmarshal uses a case-insensitive // assign to upper case fields. Unmarshal uses a case-insensitive
// comparison to match JSON field names to struct field names. // comparison to match JSON field names to struct field names.
// //
// To unmarshal a top-level JSON array, pass in a pointer to an empty
// slice of the correct type.
//
// On success, Unmarshal returns with ok set to true. // On success, Unmarshal returns with ok set to true.
// On a syntax error, it returns with ok set to false and errtok // On a syntax error, it returns with ok set to false and errtok
// set to the offending token. // set to the offending token.
func Unmarshal(s string, val interface{}) (ok bool, errtok string) { func Unmarshal(s string, val interface{}) (ok bool, errtok string) {
b := &structBuilder{val: reflect.NewValue(val)}; v := reflect.NewValue(val);
var b *structBuilder;
// If val is a pointer to a slice, we mutate the pointee.
if ptr, ok := v.(*reflect.PtrValue); ok {
if slice, ok := ptr.Elem().(*reflect.SliceValue); ok {
b = &structBuilder{val: slice}
}
}
if b == nil {
b = &structBuilder{val: v}
}
ok, _, errtok = Parse(s, b); ok, _, errtok = Parse(s, b);
if !ok { if !ok {
return false, errtok return false, errtok
......
...@@ -126,9 +126,34 @@ func TestIssue147(t *testing.T) { ...@@ -126,9 +126,34 @@ func TestIssue147(t *testing.T) {
var timeline Issue147; var timeline Issue147;
Unmarshal(issue147Input, &timeline); Unmarshal(issue147Input, &timeline);
if len(timeline.Test) != 30 {
t.Errorf("wrong length: got %d want 30", len(timeline.Test))
}
for i, e := range timeline.Test { for i, e := range timeline.Test {
if e.Text != strconv.Itoa(i) { if e.Text != strconv.Itoa(i) {
t.Errorf("index: %d got: %s want: %d", i, e.Text, i) t.Errorf("index: %d got: %s want: %d", i, e.Text, i)
} }
} }
} }
type Issue114 struct {
Text string;
}
const issue114Input = `[{"text" : "0"}, {"text" : "1"}, {"text" : "2"}, {"text" : "3"}]`
func TestIssue114(t *testing.T) {
var items []Issue114;
Unmarshal(issue114Input, &items);
if len(items) != 4 {
t.Errorf("wrong length: got %d want 4", len(items))
}
for i, e := range items {
if e.Text != strconv.Itoa(i) {
t.Errorf("index: %d got: %s want: %d", i, e.Text, i)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment