mirror of
https://github.com/golang/go
synced 2024-11-22 09:44:40 -07:00
Add json.Marshal to json package
R=rsc CC=golang-dev https://golang.org/cl/157068
This commit is contained in:
parent
121bb921fb
commit
ce88bfa585
@ -8,6 +8,9 @@
|
|||||||
package json
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt";
|
||||||
|
"io";
|
||||||
|
"os";
|
||||||
"reflect";
|
"reflect";
|
||||||
"strings";
|
"strings";
|
||||||
)
|
)
|
||||||
@ -306,3 +309,97 @@ func Unmarshal(s string, val interface{}) (ok bool, errtok string) {
|
|||||||
}
|
}
|
||||||
return true, "";
|
return true, "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MarshalError struct {
|
||||||
|
T reflect.Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MarshalError) String() string {
|
||||||
|
return "json cannot encode value of type " + e.T.String()
|
||||||
|
}
|
||||||
|
func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) os.Error {
|
||||||
|
fmt.Fprint(w, "[");
|
||||||
|
|
||||||
|
for i := 0; i < val.Len(); i++ {
|
||||||
|
if err := writeValue(w, val.Elem(i)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < val.Len()-1 {
|
||||||
|
fmt.Fprint(w, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(w, "]");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeMap(w io.Writer, val *reflect.MapValue) os.Error {
|
||||||
|
key := val.Type().(*reflect.MapType).Key();
|
||||||
|
if _, ok := key.(*reflect.StringType); !ok {
|
||||||
|
return &MarshalError{val.Type()}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := val.Keys();
|
||||||
|
fmt.Fprint(w, "{");
|
||||||
|
for i := 0; i < len(keys); i++ {
|
||||||
|
fmt.Fprintf(w, "%q:", keys[i].(*reflect.StringValue).Get());
|
||||||
|
|
||||||
|
if err := writeValue(w, val.Elem(keys[i])); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < len(keys)-1 {
|
||||||
|
fmt.Fprint(w, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(w, "}");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeStruct(w io.Writer, val *reflect.StructValue) os.Error {
|
||||||
|
fmt.Fprint(w, "{");
|
||||||
|
|
||||||
|
typ := val.Type().(*reflect.StructType);
|
||||||
|
|
||||||
|
for i := 0; i < val.NumField(); i++ {
|
||||||
|
fieldValue := val.Field(i);
|
||||||
|
fmt.Fprintf(w, "%q:", typ.Field(i).Name);
|
||||||
|
writeValue(w, fieldValue);
|
||||||
|
if i < val.NumField()-1 {
|
||||||
|
fmt.Fprint(w, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(w, "}");
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
|
||||||
|
switch v := val.(type) {
|
||||||
|
case *reflect.StringValue:
|
||||||
|
fmt.Fprintf(w, "%q", v.Get())
|
||||||
|
case *reflect.ArrayValue:
|
||||||
|
err = writeArrayOrSlice(w, v)
|
||||||
|
case *reflect.SliceValue:
|
||||||
|
err = writeArrayOrSlice(w, v)
|
||||||
|
case *reflect.MapValue:
|
||||||
|
err = writeMap(w, v)
|
||||||
|
case *reflect.StructValue:
|
||||||
|
err = writeStruct(w, v)
|
||||||
|
case *reflect.ChanValue,
|
||||||
|
*reflect.InterfaceValue,
|
||||||
|
*reflect.PtrValue,
|
||||||
|
*reflect.UnsafePointerValue:
|
||||||
|
return &MarshalError{val.Type()}
|
||||||
|
default:
|
||||||
|
value := val.(reflect.Value);
|
||||||
|
fmt.Fprint(w, value.Interface());
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
func Marshal(w io.Writer, val interface{}) os.Error {
|
||||||
|
return writeValue(w, reflect.NewValue(val))
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package json
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes";
|
||||||
"reflect";
|
"reflect";
|
||||||
"strconv";
|
"strconv";
|
||||||
"testing";
|
"testing";
|
||||||
@ -157,3 +158,48 @@ func TestIssue114(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type marshalTest struct {
|
||||||
|
val interface{};
|
||||||
|
out string;
|
||||||
|
}
|
||||||
|
|
||||||
|
var marshalTests = []marshalTest{
|
||||||
|
// basic string
|
||||||
|
marshalTest{true, "true"},
|
||||||
|
marshalTest{false, "false"},
|
||||||
|
marshalTest{123, "123"},
|
||||||
|
marshalTest{0.1, "0.1"},
|
||||||
|
marshalTest{1e-10, "1e-10"},
|
||||||
|
marshalTest{"teststring", `"teststring"`},
|
||||||
|
marshalTest{[4]int{1, 2, 3, 4}, "[1,2,3,4]"},
|
||||||
|
marshalTest{[]int{1, 2, 3, 4}, "[1,2,3,4]"},
|
||||||
|
marshalTest{[][]int{[]int{1, 2}, []int{3, 4}}, "[[1,2],[3,4]]"},
|
||||||
|
marshalTest{map[string]string{"one": "one"}, `{"one":"one"}`},
|
||||||
|
marshalTest{map[string]int{"one": 1}, `{"one":1}`},
|
||||||
|
marshalTest{struct{}{}, "{}"},
|
||||||
|
marshalTest{struct{ a int }{1}, `{"a":1}`},
|
||||||
|
marshalTest{struct {
|
||||||
|
a int;
|
||||||
|
b string;
|
||||||
|
}{1, "hello"},
|
||||||
|
`{"a":1,"b":"hello"}`,
|
||||||
|
},
|
||||||
|
marshalTest{map[string][]int{"3": []int{1, 2, 3}}, `{"3":[1,2,3]}`},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJsonMarshal(t *testing.T) {
|
||||||
|
for _, tt := range marshalTests {
|
||||||
|
var buf bytes.Buffer;
|
||||||
|
|
||||||
|
err := Marshal(&buf, tt.val);
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error converting %s to JSON: \n", err.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
s := buf.String();
|
||||||
|
if s != tt.out {
|
||||||
|
t.Errorf("Error converting to JSON. Expected: %q Actual %q\n", tt.out, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user