From 289a357104854d5f58102b05b40154c727657408 Mon Sep 17 00:00:00 2001 From: Francisco Souza Date: Thu, 22 Mar 2012 18:25:40 +1100 Subject: [PATCH] doc: add JSON and Go article Originally published on The Go Programming Language Blog, January 25, 2011. http://blog.golang.org/2011/01/json-and-go.html R=adg CC=golang-dev https://golang.org/cl/5846044 --- doc/Makefile | 1 + doc/articles/json_and_go.html | 356 ++++++++++++++++++++++++++++++++ doc/docs.html | 2 +- doc/progs/json1.go | 88 ++++++++ doc/progs/json2.go | 42 ++++ doc/progs/json3.go | 73 +++++++ doc/progs/json4.go | 45 ++++ doc/progs/json5.go | 31 +++ doc/progs/run | 14 +- src/pkg/encoding/json/encode.go | 2 +- 10 files changed, 651 insertions(+), 3 deletions(-) create mode 100644 doc/articles/json_and_go.html create mode 100644 doc/progs/json1.go create mode 100644 doc/progs/json2.go create mode 100644 doc/progs/json3.go create mode 100644 doc/progs/json4.go create mode 100644 doc/progs/json5.go 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: +

+ + + +

+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): +

+ + + +

+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: + + + +

+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