Golang iterate over nested struct - json

i want to iterate over a nested json struct in golang. The issue is, i do not exactly know how nested the structure will be, becuase there are multiple jsons. In this case for example the output should be:
"available": false
"type": "foo"
"name": "foo"
"street": "foo"
....
Is that possible?
{
"informations": {
"available": false,
"provide": {
"informations": {
"customer": {
"type": "foo",
"address": {
"name": "foo",
"street": "foo",
"zipcode": "123",
"city": "foo"
}
}
}
}
}
}

I think you can do this with a map[string]interface{}. Because, as you said that you don't know exactly the structure of the JSON. But, again, you need to know the JSON structure each time while extracting data. Also, you need to do type assertion for inner map[string]interface{}. You can look at the answer from here for type assertion.
Here's the example code that I wrote:
package main
import (
"encoding/json"
"fmt"
)
var j = `{
"informations": {
"available": false,
"provide": {
"informations": {
"customer": {
"type": "foo",
"address": {
"name": "foo",
"street": "foo",
"zipcode": "123",
"city": "foo"
}
}
}
}
}
}`
func main() {
var data map[string]interface{}
err := json.Unmarshal([]byte(j), &data)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(data["informations"])
information := data["informations"]
provide := information.(map[string]interface{})["provide"]
fmt.Println(provide)
}
Output will be:
map[available:false provide:map[informations:map[customer:map[address:map[city:foo name:foo street:foo zipcode:123] type:foo]]]]
map[informations:map[customer:map[address:map[city:foo name:foo street:foo zipcode:123] type:foo]]]
Go Playground

Related

How to get all objects with jsonpaths in golang

I am using jsonpath in golang but I can't get all the objects of the following json that contain in type iPhone:
{
"firstName": "John",
"lastName": "doe",
"age": 26,
"address": {
"streetAddress": "naist street",
"city": "Nara",
"postalCode": "630-0192"
},
"phoneNumbers": [
{
"type": "iPhone",
"number": "0123-4567-8888"
},
{
"type": "home",
"number": "0123-4567-8910"
},
{
"type": "iPhone",
"number": "0123-4567-8910"
}
]}
I am working with golang and I know that the following jsonpath works:
$.phoneNumbers[?(#.type == "iPhone")]
The problem I have is that it is a service in which I have input a json path like the following:
$.[*].phoneNumbers[*].type
And the value that I have to look for, I am doing it in the following way:
values, err := jsonpath.Get(jsonPath, data)
for _, value := range values {
if err != nil {
continue
}
if value.(string) == "iPhone" {
}
}
At this point I cant get the output like:
[{
"type": "iPhone",
"number": "0123-4567-8888"
},
{
"type": "iPhone",
"number": "0123-4567-8888"
}]
I cant use the [?(#.)] format it is necessary to make with if.
Any idea?
Thanks
I cooked up an example using Peter Ohler's ojg package. Here's what the implementation looks like:
package main
import (
"fmt"
"github.com/ohler55/ojg/jp"
"github.com/ohler55/ojg/oj"
)
var jsonString string = `{
// Your JSON string
}`
func main() {
obj, err := oj.ParseString(jsonString)
if err != nil {
panic(err)
}
x, err := jp.ParseString(`$.phoneNumbers[?(#.type == "iPhone")]`)
if err != nil {
panic(err)
}
ys := x.Get(obj)
for k, v := range ys {
fmt.Println(k, "=>", v)
}
}
// Output:
// 0 => map[number:0123-4567-8888 type:iPhone]
// 1 => map[number:0123-4567-8910 type:iPhone]
Go Playground

Enumerate slice entries

If I have this output
Stuff {
"Items": [
{
"title": "test1",
"id": "1",
},
{
"title": "test",
"id": "2",
},
],
"total": 19
},
}
But want this instead:
stuff {
"Items": [
1:{
"title": "test1",
"id": "1",
},
2:{
"title": "test",
"id": "2",
},
],
"total": 19
},
}
Currently, my structs are build like this:
Stuff struct {
Items []Items `json:"items"`
Total int `json:"total"`
} `json:"stuff"`
type Items struct {
Title string `json:"title"`
ID string `json:"id"`
}
I initiate a slice by:
stuff := make([]Items, 10) // Lets say I have 10 entries
And append by:
Stuff.Items = stuff
Stuff.Total = len(Stuff.Items)
Now I am unsure on how to numerate that. So for every item entries, there should be a number, starting from 1 - 10 (In this example)
Given your Stuff and Items type declarations, here's a simple data structure and its JSON dump:
s := Stuff{Items: []Items{Items{"test1", "1"}, Items{"test2", "2"}}, Total: 10}
j, err := json.MarshalIndent(s, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(j))
JSON:
{
"items": [
{
"title": "test1",
"id": "1"
},
{
"title": "test2",
"id": "2"
}
],
"total": 10
}
To see what you want instead, there's no magic json package call to do that. You'll have to create a new data structure that reflects the structure of your desired output.
In this case a simple map will do:
m := make(map[string]Items)
for _, item := range s.Items {
m[item.ID] = item
}
And now if you JSON-dump this map, you get:
{
"1": {
"title": "test1",
"id": "1"
},
"2": {
"title": "test2",
"id": "2"
}
}
Note that I'm not wrapping it with Stuff now, because Stuff has different fields. Go is statically typed, and each struct can only contain the fields you declared it to have.

How to Read JSON in Go Lang

I have the following JSON array received as a web service output using CURL.
{
"total_rows": 4,
"offset": 0,
"rows": [
{
"id": "_design/people",
"key": "_design/people",
"value": {
"rev": "3-d707964c8a3fa0c0c71e51c600bbafb8"
}
},
{
"id": "aamir",
"key": "aamir",
"value": {
"rev": "3-4b9095435470366fb77df1a3d466bcff"
}
},
{
"id": "iyaan",
"key": "iyaan",
"value": {
"rev": "1-4fea2c459d85480bf4841c7e581180c0"
}
},
{
"id": "tahir",
"key": "tahir",
"value": {
"rev": "2-593c9237a96836a98f53c0374902964a"
}
}
]
}
I want to extract the "total_rows" object separately from it and "rows" object separately.
You just need the package encoding/json.
Defined Row struct:
type Row struct {
Id string `json:"id"`
Key string `json:"key"`
Value struct {
Rev string `json:"rev"`
} `json:"value"`
}
Defined Data Sturct:
type Data struct {
TotalRows int `json:"total_rows"`
Offset int `json:"offest"`
Rows []Row `json:"rows"`
}
And then use json.Unmarshal:
b := []byte("json string")
data := Data{}
if err := json.Unmarshal(b, &data); err != nil {
panic(err)
}
fmt.Println(data.TotalRows, data.Offset)
for _, row := range data.Rows {
fmt.Println(row.Id, row.Key)
}
As the other poster suggested, "encoding/json" will set you up with what you need. I will also recommend trying some of the third party libraries as they can maybe better fit your implementation. Initially I would suggest looking at:
https://github.com/buger/jsonparser
https://github.com/mailru/easyjson
These are just some quick suggestions and there are other libraries out there. Good luck!

How to create custom key in json response using golang

I get a following json response through golang.
[
{
"CreatedOn": "03-22-2015",
"JSONReceived": [
{
"EzpOrderID": "ezp_126",
"FirstName": "Kumar",
"LastName": "S",
"OrderDesc": "Sample"
}
],
"Status": "0",
"id": "80acbdad-8aae-4d6c-ac63-2a02a9db64b4"
},
{
"CreatedOn": "03-22-2015",
"JSONReceived": [
{
"EzpOrderID": "ezp_126",
"FirstName": "Vasanth",
"LastName": "K",
"OrderDesc": "Sample"
}
],
"Status": "0",
"id": "8f7f52a5-793a-45bd-a9b7-ed41495e0ee3"
}
]..
But i need to create with key in response. sample response as follows. How to achieve using golang programming.
{
"returnResponseData": [{
"CreatedOn": "03-22-2015",
"JSONReceived": [{
"EzpOrderID": "ezp_126",
"FirstName": "Kumar",
"LastName": "S",
"OrderDesc": "Sample"
}],
"Status": "0",
"id": "80acbdad-8aae-4d6c-ac63-2a02a9db64b4"
}, {
"CreatedOn": "03-22-2015",
"JSONReceived": [{
"EzpOrderID": "ezp_126",
"FirstName": "Vasanth",
"LastName": "K",
"OrderDesc": "Sample"
}],
"Status": "0",
"id": "8f7f52a5-793a-45bd-a9b7-ed41495e0ee3"
}]
}
Please help me to achieve this task using golang.
Whole Source code as follows:
func orderList(w http.ResponseWriter, request *http.Request) {
rows, err := r.Table("orders").Run(session)
if err != nil {
fmt.Println(err)
return
}
var resultSet []interface{}
err = rows.All(&resultSet)
if err != nil {
fmt.Printf("Error scanning database result: %s", err)
return
}
if origin := request.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Header().Set("Access-Control-Allow-Headers",
"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
json.NewEncoder(w).Encode(resultSet)
}
You have to define another type like this:
type Wrapper struct {
ReturnResponseData []interface{} `json:"returnResponseData"`
}
and then encode wrapper, containing your response set:
json.NewEncoder(w).Encode(&Wrapper{ReturnResponseData: resultSet})
Notice, that you have to use property tag to achieve the name "returnResponseData", starting of a small letter (because encoder doesn't encode private properties by default).

Go structure for unmarshalling a JSON array

So I have some JSON (courtesy of the PetFinder API) that has a JSON array "pet". I want to unmarshal from it, using the "encoding/json" package, a slice of pet structs. What would this kind of structure look like? I can't find any examples of how the unmarshall function handles JSON arrays.
Here's what I was planning to do once I had a proper struct:
pfetch := new(PetsFetcher) // where PetsFetcher is the struct im asking for
err := json.Unmarshal(body, &pfetch)
And here's the json that is in body (in the form of a slice of ascii bytes):
{
"petfinder": {
"lastOffset": {
"$t": 5
},
"pets": {
"pet": [
{
"options": {
"option": [
{
"$t": "altered"
},
{
"$t": "hasShots"
},
{
"$t": "housebroken"
}
]
},
"breeds": {
"breed": {
"$t": "Dachshund"
}
}
},
{
"options": {
"option": {
"$t": "hasShots"
}
},
"breeds": {
"breed": {
"$t": "American Staffordshire Terrier"
}
},
"shelterPetId": {
"$t": "13-0164"
},
"status": {
"$t": "A"
},
"name": {
"$t": "HAUS"
}
}
]
}
}
}
Thanks in advance.
I really have no idea what those $t attributes are doing there in your JSON, so let’s answer your question with a simple example. To unmarshal this JSON:
{
"name": "something",
"options": [
{
"key": "a",
"value": "b"
},
{
"key": "c",
"value": "d"
},
{
"key": "e",
"value": "f"
},
]
}
You need this Data type in Go:
type Option struct {
Key string
Value string
}
type Data struct {
Name string
Options []Option
}
You can unmarshal a javascript array into a slice. The marhsal/unmarshalling rules are described under Marshal in the json package.
To unmarshal keys that look like "$t", you'll have to annotate the struct that it'll unpack into.
For example:
type Option struct {
Property string `json:"$t,omitempty"`
}
It may be that the $t that appear are a mistake, and are supposed to be keys in a dictionary.