mirror of
https://github.com/golang/go
synced 2024-11-22 03:14:41 -07:00
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
This commit is contained in:
parent
cec67568e9
commit
289a357104
@ -11,6 +11,7 @@ RAWHTML=\
|
|||||||
articles/go_concurrency_patterns_timing_out_moving_on.rawhtml\
|
articles/go_concurrency_patterns_timing_out_moving_on.rawhtml\
|
||||||
articles/godoc_documenting_go_code.rawhtml\
|
articles/godoc_documenting_go_code.rawhtml\
|
||||||
articles/gobs_of_data.rawhtml\
|
articles/gobs_of_data.rawhtml\
|
||||||
|
articles/json_and_go.rawhtml\
|
||||||
articles/image_draw.rawhtml\
|
articles/image_draw.rawhtml\
|
||||||
effective_go.rawhtml\
|
effective_go.rawhtml\
|
||||||
go1.rawhtml\
|
go1.rawhtml\
|
||||||
|
356
doc/articles/json_and_go.html
Normal file
356
doc/articles/json_and_go.html
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
<!--{
|
||||||
|
"Title": "JSON and Go",
|
||||||
|
"Template": true
|
||||||
|
}-->
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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,
|
||||||
|
<a href="http://json.org">json.org</a>, provides a wonderfully clear and concise
|
||||||
|
definition of the standard.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
With the <a href="/pkg/encoding/json/">json package</a> it's a snap to read and
|
||||||
|
write JSON data from your Go programs.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Encoding</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To encode JSON data we use the
|
||||||
|
<a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a> function.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
func Marshal(v interface{}) ([]byte, error)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Given the Go data structure, <code>Message</code>,
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json1.go" `/type Message/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
and an instance of <code>Message</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json1.go" `/m :=/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
we can marshal a JSON-encoded version of m using <code>json.Marshal</code>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json1.go" `/b, err :=/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If all is well, <code>err</code> will be <code>nil</code> and <code>b</code>
|
||||||
|
will be a <code>[]byte</code> containing this JSON data:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Only data structures that can be represented as valid JSON will be encoded:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
JSON objects only support strings as keys; to encode a Go map type it must be
|
||||||
|
of the form <code>map[string]T</code> (where <code>T</code> is any Go type
|
||||||
|
supported by the json package).
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Channel, complex, and function types cannot be encoded.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Cyclic data structures are not supported; they will cause <code>Marshal</code>
|
||||||
|
to go into an infinite loop.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Pointers will be encoded as the values they point to (or 'null' if the pointer
|
||||||
|
is <code>nil</code>).
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Decoding</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To decode JSON data we use the
|
||||||
|
<a href="/pkg/encoding/json/#Unmarshal"><code>Unmarshal</code></a> function.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
func Unmarshal(data []byte, v interface{}) error
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We must first create a place where the decoded data will be stored
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json1.go" `/var m Message/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
and call <code>json.Unmarshal</code>, passing it a <code>[]byte</code> of JSON
|
||||||
|
data and a pointer to <code>m</code>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json1.go" `/err := json.Unmarshal/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If <code>b</code> contains valid JSON that fits in <code>m</code>, after the
|
||||||
|
call <code>err</code> will be <code>nil</code> and the data from <code>b</code>
|
||||||
|
will have been stored in the struct <code>m</code>, as if by an assignment
|
||||||
|
like:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json1.go" `/m = Message/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
How does <code>Unmarshal</code> identify the fields in which to store the
|
||||||
|
decoded data? For a given JSON key <code>"Foo"</code>, <code>Unmarshal</code>
|
||||||
|
will look through the destination struct's fields to find (in order of
|
||||||
|
preference):
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
An exported field with a tag of <code>"Foo"</code> (see the
|
||||||
|
<a href="/ref/spec#Struct_types">Go spec</a> for more on struct tags),
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
An exported field named <code>"Foo"</code>, or
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
An exported field named <code>"FOO"</code> or <code>"FoO"</code> or some other
|
||||||
|
case-insensitive match of <code>"Foo"</code>.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
What happens when the structure of the JSON data doesn't exactly match the Go
|
||||||
|
type?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json1.go" `/"Food":"Pickle"/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<code>Unmarshal</code> 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 <code>Unmarshal</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
But what if you don't know the structure of your JSON data beforehand?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Generic JSON with interface{}</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The <code>interface{}</code> (empty interface) type describes an interface with
|
||||||
|
zero methods. Every Go type implements at least zero methods and therefore
|
||||||
|
satisfies the empty interface.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The empty interface serves as a general container type:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json2.go" `/var i interface{}/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A type assertion accesses the underlying concrete type:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json2.go" `/r := i/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Or, if the underlying type is unknown, a type switch determines the type:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json2.go" `/switch v/` `/STOP/`}}
|
||||||
|
|
||||||
|
|
||||||
|
The json package uses <code>map[string]interface{}</code> and
|
||||||
|
<code>[]interface{}</code> values to store arbitrary JSON objects and arrays;
|
||||||
|
it will happily unmarshal any valid JSON blob into a plain
|
||||||
|
<code>interface{}</code> value. The default concrete Go types are:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<code>bool</code> for JSON booleans,
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>float64</code> for JSON numbers,
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>string</code> for JSON strings, and
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>nil</code> for JSON null.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Decoding arbitrary data</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Consider this JSON data, stored in the variable <code>b</code>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json3.go" `/b :=/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Without knowing this data's structure, we can decode it into an
|
||||||
|
<code>interface{}</code> value with <code>Unmarshal</code>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json3.go" `/var f interface/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
At this point the Go value in <code>f</code> would be a map whose keys are
|
||||||
|
strings and whose values are themselves stored as empty interface values:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json3.go" `/f = map/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To access this data we can use a type assertion to access <code>f</code>'s
|
||||||
|
underlying <code>map[string]interface{}</code>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json3.go" `/m := f/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
We can then iterate through the map with a range statement and use a type switch
|
||||||
|
to access its values as their concrete types:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json3.go" `/for k, v/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In this way you can work with unknown JSON data while still enjoying the
|
||||||
|
benefits of type safety.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Reference Types</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Let's define a Go type to contain the data from the previous example:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json4.go" `/type FamilyMember/` `/STOP/`}}
|
||||||
|
|
||||||
|
{{code "/doc/progs/json4.go" `/var m FamilyMember/` `/STOP/`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Unmarshaling that data into a <code>FamilyMember</code> value works as
|
||||||
|
expected, but if we look closely we can see a remarkable thing has happened.
|
||||||
|
With the var statement we allocated a <code>FamilyMember</code> struct, and
|
||||||
|
then provided a pointer to that value to <code>Unmarshal</code>, but at that
|
||||||
|
time the <code>Parents</code> field was a <code>nil</code> slice value. To
|
||||||
|
populate the <code>Parents</code> field, <code>Unmarshal</code> allocated a new
|
||||||
|
slice behind the scenes. This is typical of how <code>Unmarshal</code> works
|
||||||
|
with the supported reference types (pointers, slices, and maps).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Consider unmarshaling into this data structure:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
type Foo struct {
|
||||||
|
Bar *Bar
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If there were a <code>Bar</code> field in the JSON object,
|
||||||
|
<code>Unmarshal</code> would allocate a new <code>Bar</code> and populate it.
|
||||||
|
If not, <code>Bar</code> would be left as a <code>nil</code> pointer.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
From this a useful pattern arises: if you have an application that receives a
|
||||||
|
few distinct message types, you might define "receiver" structure like
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
type IncomingMessage struct {
|
||||||
|
Cmd *Command
|
||||||
|
Msg *Message
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
and the sending party can populate the <code>Cmd</code> field and/or the
|
||||||
|
<code>Msg</code> field of the top-level JSON object, depending on the type of
|
||||||
|
message they want to communicate. <code>Unmarshal</code>, when decoding the
|
||||||
|
JSON into an <code>IncomingMessage</code> 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 <code>Cmd</code> or <code>Msg</code> is
|
||||||
|
not <code>nil</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Streaming Encoders and Decoders</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The json package provides <code>Decoder</code> and <code>Encoder</code> types
|
||||||
|
to support the common operation of reading and writing streams of JSON data.
|
||||||
|
The <code>NewDecoder</code> and <code>NewEncoder</code> functions wrap the
|
||||||
|
<a href="/pkg/io/#Reader"><code>io.Reader</code></a> and
|
||||||
|
<a href="/pkg/io/#Writer"><code>io.Writer</code></a> interface types.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
func NewDecoder(r io.Reader) *Decoder
|
||||||
|
func NewEncoder(w io.Writer) *Encoder
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Here's an example program that reads a series of JSON objects from standard
|
||||||
|
input, removes all but the <code>Name</code> field from each object, and then
|
||||||
|
writes the objects to standard output:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{code "/doc/progs/json5.go" `/package main/` `$`}}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Due to the ubiquity of Readers and Writers, these <code>Encoder</code> and
|
||||||
|
<code>Decoder</code> types can be used in a broad range of scenarios, such as
|
||||||
|
reading and writing to HTTP connections, WebSockets, or files.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>References</b>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For more information see the <a href="/pkg/encoding/json/">json package documentation</a>. For an example usage of
|
||||||
|
json see the source files of the <a href="/pkg/net/rpc/jsonrpc/">jsonrpc package</a>.
|
||||||
|
</p>
|
@ -113,7 +113,7 @@ Guided tours of Go programs.
|
|||||||
|
|
||||||
<h4>Packages</h4>
|
<h4>Packages</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="http://blog.golang.org/2011/01/json-and-go.html">JSON and Go</a> - using the <a href="/pkg/encoding/json/">json</a> package.</li>
|
<li><a href="/doc/articles/json_and_go.html">JSON and Go</a> - using the <a href="/pkg/encoding/json/">json</a> package.</li>
|
||||||
<li><a href="/doc/articles/gobs_of_data.html">Gobs of data</a> - the design and use of the <a href="/pkg/encoding/gob/">gob</a> package.</li>
|
<li><a href="/doc/articles/gobs_of_data.html">Gobs of data</a> - the design and use of the <a href="/pkg/encoding/gob/">gob</a> package.</li>
|
||||||
<li><a href="/doc/articles/laws_of_reflection.html">The Laws of Reflection</a> - the fundamentals of the <a href="/pkg/reflect/">reflect</a> package.</li>
|
<li><a href="/doc/articles/laws_of_reflection.html">The Laws of Reflection</a> - the fundamentals of the <a href="/pkg/reflect/">reflect</a> package.</li>
|
||||||
<li><a href="http://blog.golang.org/2011/09/go-image-package.html">The Go image package</a> - the fundamentals of the <a href="/pkg/image/">image</a> package.</li>
|
<li><a href="http://blog.golang.org/2011/09/go-image-package.html">The Go image package</a> - the fundamentals of the <a href="/pkg/image/">image</a> package.</li>
|
||||||
|
88
doc/progs/json1.go
Normal file
88
doc/progs/json1.go
Normal file
@ -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()
|
||||||
|
}
|
42
doc/progs/json2.go
Normal file
42
doc/progs/json2.go
Normal file
@ -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()
|
||||||
|
}
|
73
doc/progs/json3.go
Normal file
73
doc/progs/json3.go
Normal file
@ -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()
|
||||||
|
}
|
45
doc/progs/json4.go
Normal file
45
doc/progs/json4.go
Normal file
@ -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()
|
||||||
|
}
|
31
doc/progs/json5.go
Normal file
31
doc/progs/json5.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,15 @@ gobs="
|
|||||||
gobs2
|
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
|
for i in $all; do
|
||||||
go build $i.go
|
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 go1 '^Christmas is a holiday: true Sleeping for 0.123s.*go1.go already exists$'
|
||||||
|
|
||||||
testit interface2 "^type: float64$"
|
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"
|
rm -f $all "$TMPFILE"
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
// RFC 4627.
|
// RFC 4627.
|
||||||
//
|
//
|
||||||
// See "JSON and Go" for an introduction to this package:
|
// 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
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
Loading…
Reference in New Issue
Block a user