diff --git a/doc/Makefile b/doc/Makefile
index 547a18bb47b..da29e600b33 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -11,6 +11,7 @@ RAWHTML=\
articles/go_concurrency_patterns_timing_out_moving_on.rawhtml\
articles/godoc_documenting_go_code.rawhtml\
articles/gobs_of_data.rawhtml\
+ articles/json_and_go.rawhtml\
articles/image_draw.rawhtml\
effective_go.rawhtml\
go1.rawhtml\
diff --git a/doc/articles/json_and_go.html b/doc/articles/json_and_go.html
new file mode 100644
index 00000000000..af7776c0a47
--- /dev/null
+++ b/doc/articles/json_and_go.html
@@ -0,0 +1,356 @@
+
+
+
+JSON (JavaScript Object Notation) is a simple data interchange format.
+Syntactically it resembles the objects and lists of JavaScript. It is most
+commonly used for communication between web back-ends and JavaScript programs
+running in the browser, but it is used in many other places, too. Its home page,
+json.org, provides a wonderfully clear and concise
+definition of the standard.
+
+
+
+With the json package it's a snap to read and
+write JSON data from your Go programs.
+
+
+
+Encoding
+
+
+
+To encode JSON data we use the
+Marshal
function.
+
+
+
+func Marshal(v interface{}) ([]byte, error)
+
+
+
+Given the Go data structure, Message
,
+
+
+{{code "/doc/progs/json1.go" `/type Message/` `/STOP/`}}
+
+
+and an instance of Message
+
+
+{{code "/doc/progs/json1.go" `/m :=/`}}
+
+
+we can marshal a JSON-encoded version of m using json.Marshal
:
+
+
+{{code "/doc/progs/json1.go" `/b, err :=/`}}
+
+
+If all is well, err
will be nil
and b
+will be a []byte
containing this JSON data:
+
+
+
+b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
+
+
+
+Only data structures that can be represented as valid JSON will be encoded:
+
+
+
+-
+JSON objects only support strings as keys; to encode a Go map type it must be
+of the form
map[string]T
(where T
is any Go type
+supported by the json package).
+
+-
+Channel, complex, and function types cannot be encoded.
+
+-
+Cyclic data structures are not supported; they will cause
Marshal
+to go into an infinite loop.
+
+-
+Pointers will be encoded as the values they point to (or 'null' if the pointer
+is
nil
).
+
+
+
+
+The json package only accesses the exported fields of struct types (those that
+begin with an uppercase letter). Therefore only the the exported fields of a
+struct will be present in the JSON output.
+
+
+
+Decoding
+
+
+
+To decode JSON data we use the
+Unmarshal
function.
+
+
+
+func Unmarshal(data []byte, v interface{}) error
+
+
+
+We must first create a place where the decoded data will be stored
+
+
+{{code "/doc/progs/json1.go" `/var m Message/`}}
+
+
+and call json.Unmarshal
, passing it a []byte
of JSON
+data and a pointer to m
+
+
+{{code "/doc/progs/json1.go" `/err := json.Unmarshal/`}}
+
+
+If b
contains valid JSON that fits in m
, after the
+call err
will be nil
and the data from b
+will have been stored in the struct m
, as if by an assignment
+like:
+
+
+{{code "/doc/progs/json1.go" `/m = Message/` `/STOP/`}}
+
+
+How does Unmarshal
identify the fields in which to store the
+decoded data? For a given JSON key "Foo"
, Unmarshal
+will look through the destination struct's fields to find (in order of
+preference):
+
+
+
+-
+An exported field with a tag of
"Foo"
(see the
+Go spec for more on struct tags),
+
+-
+An exported field named
"Foo"
, or
+
+-
+An exported field named
"FOO"
or "FoO"
or some other
+case-insensitive match of "Foo"
.
+
+
+
+
+What happens when the structure of the JSON data doesn't exactly match the Go
+type?
+
+
+{{code "/doc/progs/json1.go" `/"Food":"Pickle"/` `/STOP/`}}
+
+
+Unmarshal
will decode only the fields that it can find in the
+destination type. In this case, only the Name field of m will be populated,
+and the Food field will be ignored. This behavior is particularly useful when
+you wish to pick only a few specific fields out of a large JSON blob. It also
+means that any unexported fields in the destination struct will be unaffected
+by Unmarshal
.
+
+
+
+But what if you don't know the structure of your JSON data beforehand?
+
+
+
+Generic JSON with interface{}
+
+
+
+The interface{}
(empty interface) type describes an interface with
+zero methods. Every Go type implements at least zero methods and therefore
+satisfies the empty interface.
+
+
+
+The empty interface serves as a general container type:
+
+
+{{code "/doc/progs/json2.go" `/var i interface{}/` `/STOP/`}}
+
+
+A type assertion accesses the underlying concrete type:
+
+
+{{code "/doc/progs/json2.go" `/r := i/` `/STOP/`}}
+
+
+Or, if the underlying type is unknown, a type switch determines the type:
+
+
+{{code "/doc/progs/json2.go" `/switch v/` `/STOP/`}}
+
+
+The json package uses map[string]interface{}
and
+[]interface{}
values to store arbitrary JSON objects and arrays;
+it will happily unmarshal any valid JSON blob into a plain
+interface{}
value. The default concrete Go types are:
+
+
+-
+
bool
for JSON booleans,
+
+-
+
float64
for JSON numbers,
+
+-
+
string
for JSON strings, and
+
+-
+
nil
for JSON null.
+
+
+
+
+Decoding arbitrary data
+
+
+
+Consider this JSON data, stored in the variable b
:
+
+
+{{code "/doc/progs/json3.go" `/b :=/`}}
+
+
+Without knowing this data's structure, we can decode it into an
+interface{}
value with Unmarshal
:
+
+
+{{code "/doc/progs/json3.go" `/var f interface/` `/STOP/`}}
+
+
+At this point the Go value in f
would be a map whose keys are
+strings and whose values are themselves stored as empty interface values:
+
+
+{{code "/doc/progs/json3.go" `/f = map/` `/STOP/`}}
+
+
+To access this data we can use a type assertion to access f
's
+underlying map[string]interface{}
:
+
+
+{{code "/doc/progs/json3.go" `/m := f/`}}
+
+
+We can then iterate through the map with a range statement and use a type switch
+to access its values as their concrete types:
+
+
+{{code "/doc/progs/json3.go" `/for k, v/` `/STOP/`}}
+
+
+In this way you can work with unknown JSON data while still enjoying the
+benefits of type safety.
+
+
+
+Reference Types
+
+
+
+Let's define a Go type to contain the data from the previous example:
+
+
+{{code "/doc/progs/json4.go" `/type FamilyMember/` `/STOP/`}}
+
+{{code "/doc/progs/json4.go" `/var m FamilyMember/` `/STOP/`}}
+
+
+Unmarshaling that data into a FamilyMember
value works as
+expected, but if we look closely we can see a remarkable thing has happened.
+With the var statement we allocated a FamilyMember
struct, and
+then provided a pointer to that value to Unmarshal
, but at that
+time the Parents
field was a nil
slice value. To
+populate the Parents
field, Unmarshal
allocated a new
+slice behind the scenes. This is typical of how Unmarshal
works
+with the supported reference types (pointers, slices, and maps).
+
+
+
+Consider unmarshaling into this data structure:
+
+
+
+type Foo struct {
+ Bar *Bar
+}
+
+
+
+If there were a Bar
field in the JSON object,
+Unmarshal
would allocate a new Bar
and populate it.
+If not, Bar
would be left as a nil
pointer.
+
+
+
+From this a useful pattern arises: if you have an application that receives a
+few distinct message types, you might define "receiver" structure like
+
+
+
+type IncomingMessage struct {
+ Cmd *Command
+ Msg *Message
+}
+
+
+
+and the sending party can populate the Cmd
field and/or the
+Msg
field of the top-level JSON object, depending on the type of
+message they want to communicate. Unmarshal
, when decoding the
+JSON into an IncomingMessage
struct, will only allocate the data
+structures present in the JSON data. To know which messages to process, the
+programmer need simply test that either Cmd
or Msg
is
+not nil
.
+
+
+
+Streaming Encoders and Decoders
+
+
+
+The json package provides Decoder
and Encoder
types
+to support the common operation of reading and writing streams of JSON data.
+The NewDecoder
and NewEncoder
functions wrap the
+io.Reader
and
+io.Writer
interface types.
+
+
+
+func NewDecoder(r io.Reader) *Decoder
+func NewEncoder(w io.Writer) *Encoder
+
+
+
+Here's an example program that reads a series of JSON objects from standard
+input, removes all but the Name
field from each object, and then
+writes the objects to standard output:
+
+
+{{code "/doc/progs/json5.go" `/package main/` `$`}}
+
+
+Due to the ubiquity of Readers and Writers, these Encoder
and
+Decoder
types can be used in a broad range of scenarios, such as
+reading and writing to HTTP connections, WebSockets, or files.
+
+
+
+References
+
+
+
+For more information see the json package documentation. For an example usage of
+json see the source files of the jsonrpc package.
+
diff --git a/doc/docs.html b/doc/docs.html
index 12afb7f6569..a75ae56cf29 100644
--- a/doc/docs.html
+++ b/doc/docs.html
@@ -113,7 +113,7 @@ Guided tours of Go programs.
Packages
-- JSON and Go - using the json package.
+- JSON and Go - using the json package.
- Gobs of data - the design and use of the gob package.
- The Laws of Reflection - the fundamentals of the reflect package.
- The Go image package - the fundamentals of the image package.
diff --git a/doc/progs/json1.go b/doc/progs/json1.go
new file mode 100644
index 00000000000..9e10f4743df
--- /dev/null
+++ b/doc/progs/json1.go
@@ -0,0 +1,88 @@
+// Copyright 2012 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.
+
+package main
+
+import (
+ "encoding/json"
+ "log"
+ "reflect"
+)
+
+type Message struct {
+ Name string
+ Body string
+ Time int64
+}
+
+// STOP OMIT
+
+func Encode() {
+ m := Message{"Alice", "Hello", 1294706395881547000}
+ b, err := json.Marshal(m)
+
+ if err != nil {
+ panic(err)
+ }
+
+ expected := []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
+ if !reflect.DeepEqual(b, expected) {
+ log.Panicf("Error marshalling %q, expected %q, got %q.", m, expected, b)
+ }
+
+}
+
+func Decode() {
+ b := []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
+ var m Message
+ err := json.Unmarshal(b, &m)
+
+ if err != nil {
+ panic(err)
+ }
+
+ expected := Message{
+ Name: "Alice",
+ Body: "Hello",
+ Time: 1294706395881547000,
+ }
+
+ if !reflect.DeepEqual(m, expected) {
+ log.Panicf("Error unmarshalling %q, expected %q, got %q.", b, expected, m)
+ }
+
+ m = Message{
+ Name: "Alice",
+ Body: "Hello",
+ Time: 1294706395881547000,
+ }
+
+ // STOP OMIT
+}
+
+func PartialDecode() {
+ b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
+ var m Message
+ err := json.Unmarshal(b, &m)
+
+ // STOP OMIT
+
+ if err != nil {
+ panic(err)
+ }
+
+ expected := Message{
+ Name: "Bob",
+ }
+
+ if !reflect.DeepEqual(expected, m) {
+ log.Panicf("Error unmarshalling %q, expected %q, got %q.", b, expected, m)
+ }
+}
+
+func main() {
+ Encode()
+ Decode()
+ PartialDecode()
+}
diff --git a/doc/progs/json2.go b/doc/progs/json2.go
new file mode 100644
index 00000000000..6089ae6710c
--- /dev/null
+++ b/doc/progs/json2.go
@@ -0,0 +1,42 @@
+// Copyright 2012 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.
+
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+func InterfaceExample() {
+ var i interface{}
+ i = "a string"
+ i = 2011
+ i = 2.777
+
+ // STOP OMIT
+
+ r := i.(float64)
+ fmt.Println("the circle's area", math.Pi*r*r)
+
+ // STOP OMIT
+
+ switch v := i.(type) {
+ case int:
+ fmt.Println("twice i is", v*2)
+ case float64:
+ fmt.Println("the reciprocal of i is", 1/v)
+ case string:
+ h := len(v) / 2
+ fmt.Println("i swapped by halves is", v[h:]+v[:h])
+ default:
+ // i isn't one of the types above
+ }
+
+ // STOP OMIT
+}
+
+func main() {
+ InterfaceExample()
+}
diff --git a/doc/progs/json3.go b/doc/progs/json3.go
new file mode 100644
index 00000000000..a04fdfa506a
--- /dev/null
+++ b/doc/progs/json3.go
@@ -0,0 +1,73 @@
+// Copyright 2012 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.
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "reflect"
+)
+
+func Decode() {
+ b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
+
+ var f interface{}
+ err := json.Unmarshal(b, &f)
+
+ // STOP OMIT
+
+ if err != nil {
+ panic(err)
+ }
+
+ expected := map[string]interface{}{
+ "Name": "Wednesday",
+ "Age": float64(6),
+ "Parents": []interface{}{
+ "Gomez",
+ "Morticia",
+ },
+ }
+
+ if !reflect.DeepEqual(f, expected) {
+ log.Panicf("Error unmarshalling %q, expected %q, got %q", b, expected, f)
+ }
+
+ f = map[string]interface{}{
+ "Name": "Wednesday",
+ "Age": 6,
+ "Parents": []interface{}{
+ "Gomez",
+ "Morticia",
+ },
+ }
+
+ // STOP OMIT
+
+ m := f.(map[string]interface{})
+
+ for k, v := range m {
+ switch vv := v.(type) {
+ case string:
+ fmt.Println(k, "is string", vv)
+ case int:
+ fmt.Println(k, "is int", vv)
+ case []interface{}:
+ fmt.Println(k, "is an array:")
+ for i, u := range vv {
+ fmt.Println(i, u)
+ }
+ default:
+ fmt.Println(k, "is of a type I don't know how to handle")
+ }
+ }
+
+ // STOP OMIT
+}
+
+func main() {
+ Decode()
+}
diff --git a/doc/progs/json4.go b/doc/progs/json4.go
new file mode 100644
index 00000000000..49263022065
--- /dev/null
+++ b/doc/progs/json4.go
@@ -0,0 +1,45 @@
+// Copyright 2012 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.
+
+package main
+
+import (
+ "encoding/json"
+ "log"
+ "reflect"
+)
+
+type FamilyMember struct {
+ Name string
+ Age int
+ Parents []string
+}
+
+// STOP OMIT
+
+func Decode() {
+ b := []byte(`{"Name":"Bob","Age":20,"Parents":["Morticia", "Gomez"]}`)
+ var m FamilyMember
+ err := json.Unmarshal(b, &m)
+
+ // STOP OMIT
+
+ if err != nil {
+ panic(err)
+ }
+
+ expected := FamilyMember{
+ Name: "Bob",
+ Age: 20,
+ Parents: []string{"Morticia", "Gomez"},
+ }
+
+ if !reflect.DeepEqual(expected, m) {
+ log.Panicf("Error unmarshalling %q, expected %q, got %q", b, expected, m)
+ }
+}
+
+func main() {
+ Decode()
+}
diff --git a/doc/progs/json5.go b/doc/progs/json5.go
new file mode 100644
index 00000000000..6d7a4ca8c47
--- /dev/null
+++ b/doc/progs/json5.go
@@ -0,0 +1,31 @@
+// Copyright 2012 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.
+
+package main
+
+import (
+ "encoding/json"
+ "log"
+ "os"
+)
+
+func main() {
+ dec := json.NewDecoder(os.Stdin)
+ enc := json.NewEncoder(os.Stdout)
+ for {
+ var v map[string]interface{}
+ if err := dec.Decode(&v); err != nil {
+ log.Println(err)
+ return
+ }
+ for k := range v {
+ if k != "Name" {
+ delete(v, k)
+ }
+ }
+ if err := enc.Encode(&v); err != nil {
+ log.Println(err)
+ }
+ }
+}
diff --git a/doc/progs/run b/doc/progs/run
index 1c1ac4322a0..8348a33e56e 100755
--- a/doc/progs/run
+++ b/doc/progs/run
@@ -51,7 +51,15 @@ gobs="
gobs2
"
-all=$(echo $defer_panic_recover $effective_go $error_handling $law_of_reflection $c_go_cgo $timeout $gobs slices go1)
+json="
+ json1
+ json2
+ json3
+ json4
+ json5
+"
+
+all=$(echo $defer_panic_recover $effective_go $error_handling $law_of_reflection $c_go_cgo $timeout $gobs $json slices go1)
for i in $all; do
go build $i.go
@@ -79,5 +87,9 @@ testit eff_sequence '^\[-1 2 6 16 44\]$'
testit go1 '^Christmas is a holiday: true Sleeping for 0.123s.*go1.go already exists$'
testit interface2 "^type: float64$"
+testit json1 "^$"
+testit json2 "the reciprocal of i is"
+testit json3 "Age is int 6"
+testit json4 "^$"
rm -f $all "$TMPFILE"
diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go
index edbafcf65f1..14957b8487b 100644
--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -6,7 +6,7 @@
// RFC 4627.
//
// See "JSON and Go" for an introduction to this package:
-// http://blog.golang.org/2011/01/json-and-go.html
+// http://golang.org/doc/articles/json_and_go.html
package json
import (