1![Gabs](gabs_logo.png "Gabs")
2
3Gabs is a small utility for dealing with dynamic or unknown JSON structures in
4golang. It's pretty much just a helpful wrapper around the golang
5`json.Marshal/json.Unmarshal` behaviour and `map[string]interface{}` objects.
6It does nothing spectacular except for being fabulous.
7
8https://godoc.org/github.com/Jeffail/gabs
9
10## Install
11
12``` bash
13go get github.com/Jeffail/gabs
14```
15
16## Use
17
18### Parsing and searching JSON
19
20``` go
21jsonParsed, err := gabs.ParseJSON([]byte(`{
22	"outter":{
23		"inner":{
24			"value1":10,
25			"value2":22
26		},
27		"alsoInner":{
28			"value1":20,
29			"array1":[
30				30, 40
31			]
32		}
33	}
34}`))
35
36var value float64
37var ok bool
38
39value, ok = jsonParsed.Path("outter.inner.value1").Data().(float64)
40// value == 10.0, ok == true
41
42value, ok = jsonParsed.Search("outter", "inner", "value1").Data().(float64)
43// value == 10.0, ok == true
44
45gObj, err := jsonParsed.JSONPointer("/outter/alsoInner/array1/1")
46if err != nil {
47	panic(err)
48}
49value, ok = gObj.Data().(float64)
50// value == 40.0, ok == true
51
52value, ok = jsonParsed.Path("does.not.exist").Data().(float64)
53// value == 0.0, ok == false
54
55exists := jsonParsed.Exists("outter", "inner", "value1")
56// exists == true
57
58exists := jsonParsed.ExistsP("does.not.exist")
59// exists == false
60```
61
62### Iterating objects
63
64``` go
65jsonParsed, _ := gabs.ParseJSON([]byte(`{"object":{ "first": 1, "second": 2, "third": 3 }}`))
66
67// S is shorthand for Search
68children, _ := jsonParsed.S("object").ChildrenMap()
69for key, child := range children {
70	fmt.Printf("key: %v, value: %v\n", key, child.Data().(string))
71}
72```
73
74### Iterating arrays
75
76``` go
77jsonParsed, err := gabs.ParseJSON([]byte(`{"array":[ "first", "second", "third" ]}`))
78if err != nil {
79	panic(err)
80}
81
82// S is shorthand for Search
83children, err := jsonParsed.S("array").Children()
84if err != nil {
85	panic(err)
86}
87
88for _, child := range children {
89	fmt.Println(child.Data().(string))
90}
91```
92
93Will print:
94
95```
96first
97second
98third
99```
100
101Children() will return all children of an array in order. This also works on
102objects, however, the children will be returned in a random order.
103
104### Searching through arrays
105
106If your JSON structure contains arrays you can still search the fields of the
107objects within the array, this returns a JSON array containing the results for
108each element.
109
110``` go
111jsonParsed, err := gabs.ParseJSON([]byte(`{"array":[ {"value":1}, {"value":2}, {"value":3} ]}`))
112if err != nil {
113	panic(err)
114}
115fmt.Println(jsonParsed.Path("array.value").String())
116```
117
118Will print:
119
120```
121[1,2,3]
122```
123
124### Generating JSON
125
126``` go
127jsonObj := gabs.New()
128// or gabs.Consume(jsonObject) to work on an existing map[string]interface{}
129
130jsonObj.Set(10, "outter", "inner", "value")
131jsonObj.SetP(20, "outter.inner.value2")
132jsonObj.Set(30, "outter", "inner2", "value3")
133
134fmt.Println(jsonObj.String())
135```
136
137Will print:
138
139```
140{"outter":{"inner":{"value":10,"value2":20},"inner2":{"value3":30}}}
141```
142
143To pretty-print:
144
145``` go
146fmt.Println(jsonObj.StringIndent("", "  "))
147```
148
149Will print:
150
151```
152{
153  "outter": {
154    "inner": {
155      "value": 10,
156      "value2": 20
157    },
158    "inner2": {
159      "value3": 30
160    }
161  }
162}
163```
164
165### Generating Arrays
166
167``` go
168jsonObj := gabs.New()
169
170jsonObj.Array("foo", "array")
171// Or .ArrayP("foo.array")
172
173jsonObj.ArrayAppend(10, "foo", "array")
174jsonObj.ArrayAppend(20, "foo", "array")
175jsonObj.ArrayAppend(30, "foo", "array")
176
177fmt.Println(jsonObj.String())
178```
179
180Will print:
181
182```
183{"foo":{"array":[10,20,30]}}
184```
185
186Working with arrays by index:
187
188``` go
189jsonObj := gabs.New()
190
191// Create an array with the length of 3
192jsonObj.ArrayOfSize(3, "foo")
193
194jsonObj.S("foo").SetIndex("test1", 0)
195jsonObj.S("foo").SetIndex("test2", 1)
196
197// Create an embedded array with the length of 3
198jsonObj.S("foo").ArrayOfSizeI(3, 2)
199
200jsonObj.S("foo").Index(2).SetIndex(1, 0)
201jsonObj.S("foo").Index(2).SetIndex(2, 1)
202jsonObj.S("foo").Index(2).SetIndex(3, 2)
203
204fmt.Println(jsonObj.String())
205```
206
207Will print:
208
209```
210{"foo":["test1","test2",[1,2,3]]}
211```
212
213### Converting back to JSON
214
215This is the easiest part:
216
217``` go
218jsonParsedObj, _ := gabs.ParseJSON([]byte(`{
219	"outter":{
220		"values":{
221			"first":10,
222			"second":11
223		}
224	},
225	"outter2":"hello world"
226}`))
227
228jsonOutput := jsonParsedObj.String()
229// Becomes `{"outter":{"values":{"first":10,"second":11}},"outter2":"hello world"}`
230```
231
232And to serialize a specific segment is as simple as:
233
234``` go
235jsonParsedObj := gabs.ParseJSON([]byte(`{
236	"outter":{
237		"values":{
238			"first":10,
239			"second":11
240		}
241	},
242	"outter2":"hello world"
243}`))
244
245jsonOutput := jsonParsedObj.Search("outter").String()
246// Becomes `{"values":{"first":10,"second":11}}`
247```
248
249### Merge two containers
250
251You can merge a JSON structure into an existing one, where collisions will be
252converted into a JSON array.
253
254``` go
255jsonParsed1, _ := ParseJSON([]byte(`{"outter": {"value1": "one"}}`))
256jsonParsed2, _ := ParseJSON([]byte(`{"outter": {"inner": {"value3": "three"}}, "outter2": {"value2": "two"}}`))
257
258jsonParsed1.Merge(jsonParsed2)
259// Becomes `{"outter":{"inner":{"value3":"three"},"value1":"one"},"outter2":{"value2":"two"}}`
260```
261
262Arrays are merged:
263
264``` go
265jsonParsed1, _ := ParseJSON([]byte(`{"array": ["one"]}`))
266jsonParsed2, _ := ParseJSON([]byte(`{"array": ["two"]}`))
267
268jsonParsed1.Merge(jsonParsed2)
269// Becomes `{"array":["one", "two"]}`
270```
271
272### Parsing Numbers
273
274Gabs uses the `json` package under the bonnet, which by default will parse all
275number values into `float64`. If you need to parse `Int` values then you should
276use a `json.Decoder` (https://golang.org/pkg/encoding/json/#Decoder):
277
278``` go
279sample := []byte(`{"test":{"int":10, "float":6.66}}`)
280dec := json.NewDecoder(bytes.NewReader(sample))
281dec.UseNumber()
282
283val, err := gabs.ParseJSONDecoder(dec)
284if err != nil {
285    t.Errorf("Failed to parse: %v", err)
286    return
287}
288
289intValue, err := val.Path("test.int").Data().(json.Number).Int64()
290```
291