-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpickjson.go
More file actions
137 lines (109 loc) · 2.52 KB
/
pickjson.go
File metadata and controls
137 lines (109 loc) · 2.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package pickjson
import (
"encoding/json"
"io"
)
func processToken(reader io.Reader, key string, hook func(*json.Decoder) bool) {
decoder := json.NewDecoder(reader)
// if empty key -> hook the whole decoder
// only for #PickObject root object
if key == "" {
hook(decoder)
return
}
isKey := true
for {
token, err := decoder.Token()
// return when done
if err == io.EOF {
break
}
// stop on error
if err != nil {
break
}
// start process the tokens
switch token.(type) {
case json.Delim: // { } [ ]
isKey = true
case string: // key or value
if isKey && key == token {
stop := hook(decoder)
if stop {
return
}
}
isKey = !isKey
default:
isKey = !isKey
}
}
return
}
// PickString pick String by key, return empty array if there is no matching key or error
func PickString(reader io.Reader, key string, limit int) (res []string) {
processToken(reader, key, func(decoder *json.Decoder) bool {
// matched token
token, err := decoder.Token()
// skip the error token
if err != nil {
return false
}
if tokenStr, ok := token.(string); ok {
res = append(res, tokenStr)
if limit > 0 && len(res) >= limit {
return true
}
}
return false
})
return
}
// PickBool pick Bool by key, return empty array if there is no matching key or error
func PickBool(reader io.Reader, key string, limit int) (res []bool) {
processToken(reader, key, func(decoder *json.Decoder) bool {
// matched token
token, err := decoder.Token()
// skip the error token
if err != nil {
return false
}
if tokenStr, ok := token.(bool); ok {
res = append(res, tokenStr)
if limit > 0 && len(res) >= limit {
return true
}
}
return false
})
return
}
// PickNumber pick Float64 by key, return empty array if there is no matching key or error
func PickNumber(reader io.Reader, key string, limit int) (res []float64) {
processToken(reader, key, func(decoder *json.Decoder) bool {
// matched token
token, err := decoder.Token()
// skip the error token
if err != nil {
return false
}
if tokenStr, ok := token.(float64); ok {
res = append(res, tokenStr)
if limit > 0 && len(res) >= limit {
return true
}
}
return false
})
return
}
// PickObject pick struct by key
// there is no limit for PickObject yet :(
// TODO: add limit
func PickObject(reader io.Reader, key string, object interface{}) (err error) {
processToken(reader, key, func(decoder *json.Decoder) bool {
err = decoder.Decode(object)
return true
})
return
}