Skip to content

Commit 0cf48b4

Browse files
peterwaldrsc
authored andcommitted
encoding/json: add JSON streaming parse API
This change adds new methods to Decoder. * Decoder.Token steps through a JSON document, returning a value for each token. * Decoder.Decode unmarshals the entire value at the token stream's current position (in addition to its existing function in a stream of JSON values) Fixes #6050. Fixes #6499. Change-Id: Iff283e0e7b537221ae256392aca6529f06ebe211 Reviewed-on: https://go-review.googlesource.com/9073 Reviewed-by: Russ Cox <[email protected]>
1 parent 9c55792 commit 0cf48b4

File tree

4 files changed

+518
-23
lines changed

4 files changed

+518
-23
lines changed

src/encoding/json/bench_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"compress/gzip"
1616
"io/ioutil"
1717
"os"
18+
"strings"
1819
"testing"
1920
)
2021

@@ -126,6 +127,28 @@ func BenchmarkCodeDecoder(b *testing.B) {
126127
b.SetBytes(int64(len(codeJSON)))
127128
}
128129

130+
func BenchmarkDecoderStream(b *testing.B) {
131+
b.StopTimer()
132+
var buf bytes.Buffer
133+
dec := NewDecoder(&buf)
134+
buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n")
135+
var x interface{}
136+
if err := dec.Decode(&x); err != nil {
137+
b.Fatal("Decode:", err)
138+
}
139+
ones := strings.Repeat(" 1\n", 300000) + "\n\n\n"
140+
b.StartTimer()
141+
for i := 0; i < b.N; i++ {
142+
if i%300000 == 0 {
143+
buf.WriteString(ones)
144+
}
145+
x = nil
146+
if err := dec.Decode(&x); err != nil || x != 1.0 {
147+
b.Fatalf("Decode: %v after %d", err, i)
148+
}
149+
}
150+
}
151+
129152
func BenchmarkCodeUnmarshal(b *testing.B) {
130153
if codeJSON == nil {
131154
b.StopTimer()

src/encoding/json/example_test.go

+91
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,97 @@ func ExampleDecoder() {
8383
// Ed: Go fmt yourself!
8484
}
8585

86+
// This example uses a Decoder to decode a stream of distinct JSON values.
87+
func ExampleDecoder_Token() {
88+
const jsonStream = `
89+
{"Message": "Hello", "Array": [1, 2, 3], "Null": null, "Number": 1.234}
90+
`
91+
dec := json.NewDecoder(strings.NewReader(jsonStream))
92+
for {
93+
t, err := dec.Token()
94+
if err == io.EOF {
95+
break
96+
}
97+
if err != nil {
98+
log.Fatal(err)
99+
}
100+
fmt.Printf("%T: %v", t, t)
101+
if dec.More() {
102+
fmt.Printf(" (more)")
103+
}
104+
fmt.Printf("\n")
105+
}
106+
// Output:
107+
// json.Delim: { (more)
108+
// string: Message (more)
109+
// string: Hello (more)
110+
// string: Array (more)
111+
// json.Delim: [ (more)
112+
// float64: 1 (more)
113+
// float64: 2 (more)
114+
// float64: 3
115+
// json.Delim: ] (more)
116+
// string: Null (more)
117+
// <nil>: <nil> (more)
118+
// string: Number (more)
119+
// float64: 1.234
120+
// json.Delim: }
121+
}
122+
123+
// This example uses a Decoder to decode a streaming array of JSON objects.
124+
func ExampleDecoder_Decode_stream() {
125+
const jsonStream = `
126+
[
127+
{"Name": "Ed", "Text": "Knock knock."},
128+
{"Name": "Sam", "Text": "Who's there?"},
129+
{"Name": "Ed", "Text": "Go fmt."},
130+
{"Name": "Sam", "Text": "Go fmt who?"},
131+
{"Name": "Ed", "Text": "Go fmt yourself!"}
132+
]
133+
`
134+
type Message struct {
135+
Name, Text string
136+
}
137+
dec := json.NewDecoder(strings.NewReader(jsonStream))
138+
139+
// read open bracket
140+
t, err := dec.Token()
141+
if err != nil {
142+
log.Fatal(err)
143+
}
144+
fmt.Printf("%T: %v\n", t, t)
145+
146+
var m Message
147+
// while the array contains values
148+
for dec.More() {
149+
150+
// decode an array value (Message)
151+
err := dec.Decode(&m)
152+
if err != nil {
153+
log.Fatal(err)
154+
}
155+
156+
fmt.Printf("%v: %v\n", m.Name, m.Text)
157+
}
158+
159+
// read closing bracket
160+
t, err = dec.Token()
161+
if err != nil {
162+
log.Fatal(err)
163+
}
164+
fmt.Printf("%T: %v\n", t, t)
165+
166+
// Output:
167+
// json.Delim: [
168+
// Ed: Knock knock.
169+
// Sam: Who's there?
170+
// Ed: Go fmt.
171+
// Sam: Go fmt who?
172+
// Ed: Go fmt yourself!
173+
// json.Delim: ]
174+
175+
}
176+
86177
// This example uses RawMessage to delay parsing part of a JSON message.
87178
func ExampleRawMessage() {
88179
type Color struct {

0 commit comments

Comments
 (0)