Parsing a JSON array of JSON objects? - arrays

I am trying to get each JSON object out of a JSON array. I get this data via a HTTP post.
I know what my data will look like:
{
"array":[
{
"entity_title":"University of Phoenix",
"entity_org_name":"CS Club",
"possible_user_name":"Johnny Ive",
"posibble_user_email":"Johhny.Ive#uop.edu",
"user_position_title":"President",
"msg_body_id":4
},
{
"entity_title":"University of San Francisco",
"entity_org_name":"Marketing club",
"possible_user_name":"steve jobs",
"posibble_user_email":"steven.job#uop.edu",
"user_position_title":"Student",
"msg_body_id":5
}
]
}
My example code and my structs look like this:
type MsgCreateUserArray struct {
CreateUser []MsgCreateUserJson `json:"createUserArray"`
}
type MsgCreateUserJson struct {
EntityTitleName string `json:"entity_title_name"`
EntityOrgName string `json:"entity_org_name"`
PossibleUserName string `json:"possible_user_name"`
PossibleUserEmail string `json:"possible_user_email"`
UserPositionTitle string `json:"user_position_title"`
MsgBodyId string `json:"msg_body_id, omitempty"`
}
func parseJson(rw http.ResponseWriter, request *http.Request) {
decodeJson := json.NewDecoder(request.Body)
var msg MsgCreateUserArray
err := decodeJson.Decode(&msg)
if err != nil {
panic(err)
}
log.Println(msg.CreateUser)
}
func main() {
http.HandleFunc("/", parseJson)
http.ListenAndServe(":1337", nil)
}
I am not sure where how to iterate over the JSON array and get the JSON objects and then just work with the JSON objects.

Try this as your structs,
type MsgCreateUserArray struct {
CreateUser []MsgCreateUserJson `json:"array"`
}
type MsgCreateUserJson struct {
EntityOrgName string `json:"entity_org_name"`
EntityTitle string `json:"entity_title"`
MsgBodyID int64 `json:"msg_body_id,omitempty"`
PosibbleUserEmail string `json:"posibble_user_email"`
PossibleUserName string `json:"possible_user_name"`
UserPositionTitle string `json:"user_position_title"`
}
Your entity_title_name is not named correctly, nor is the top level array. After you decode into a MsgCreateUserArray you can iterate over the CreateUser slice to get each MsgCreateUserJson

Related

JSON Arrays as Go Structs

I am trying to call an array of objects from my JSON file but I am always facing an error saying: "cannot unmarshal array into Go value of type config.APPConfig".
How can I ensure the configs how my Go struct calls the array of objects within my JSON file?
Here are both my config file in which I set up the Go structs and the JSON file:
Config.go
package config
import (
"encoding/json"
"io/ioutil"
)
type Easy struct {
UID string `json:"uId"`
}
type Auth struct {
Code string `json:"code"`
}
type APPConfig struct {
OpenAPIMode string `json:"openAPIMode"`
OpenAPIURL string `json:"openAPIUrl"`
ClientID string `json:"clientId"`
Secret string `json:"secret"`
AuthMode string `json:"authMode"`
Easy Easy `json:"easy"`
Auth Auth `json:"auth"`
DeviceID string `json:"deviceId"`
UID string `json:"-"`
MQTTUID string `json:"-"`
AccessToken string `json:"-"`
RefreshToken string `json:"-"`
ExpireTime int64 `json:"-"`
}
var App = APPConfig{
OpenAPIMode: "mqtt",
OpenAPIURL: "openapi.tuyacn.com",
}
func LoadConfig() error {
return parseJSON("webrtc.json", &App)
}
func parseJSON(path string, v interface{}) error {
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, v)
return err
}
JSON file
[
{
"openAPIMode": "mqtt",
"openAPIUrl": "openapi.tuyaus.com",
"clientId": "*****",
"secret": "**************",
"authMode": "easy",
"easy": {
"uId": "**********"
},
"auth": {
"code": ""
},
"deviceId": "***********"
},
{
"openAPIMode": "mqtt",
"openAPIUrl": "openapi.tuyaus.com",
"clientId": "*****",
"secret": "**************",
"authMode": "easy",
"easy": {
"uId": "**********"
},
"auth": {
"code": ""
},
"deviceId": "***********"
}
]
Thanks in advance for helping!
Your config json file is an Array of JSON and you are parsing it to struct you need to parse it to array of struct.
To fix your code change the initialization of App to this.
var App []APPConfig
func LoadConfig() error {
return parseJSON("webrtc.json", &App)
}
Here's example full code for it.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Easy struct {
UID string `json:"uId"`
}
type Auth struct {
Code string `json:"code"`
}
type APPConfig struct {
OpenAPIMode string `json:"openAPIMode"`
OpenAPIURL string `json:"openAPIUrl"`
ClientID string `json:"clientId"`
Secret string `json:"secret"`
AuthMode string `json:"authMode"`
Easy Easy `json:"easy"`
Auth Auth `json:"auth"`
DeviceID string `json:"deviceId"`
UID string `json:"-"`
MQTTUID string `json:"-"`
AccessToken string `json:"-"`
RefreshToken string `json:"-"`
ExpireTime int64 `json:"-"`
}
var App []APPConfig
func LoadConfig() error {
return parseJSON("webrtc.json", &App)
}
func parseJSON(path string, v interface{}) error {
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, v)
return err
}
func main() {
err := LoadConfig()
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", App)
}

How to encode/marshal response from my server in multiple object JSON array

I am trying to format my response from a server in an array of multiple object JSON. I tried slice and []Struct but I believe I am not able to understand their usage correctly.
I tried the method mentioned here - https://play.golang.org/p/9OEPzbf0Me0 but didn't work in my case
I am using golang to get response for a query parameter
router.HandleFunc("/v1.0/singles", GetInfo).Methods("GET").Queries("Group", "{group}")
//controller.go
func SendToServer(jsonValue []byte, command string) (models.JSON, error) {
var pdatar models.JSON
s := []string{"http://172.xx.xxx.xx:xxxxx/", command}
response, err := http.Post(strings.Join(s, ""), "application/json", bytes.NewBuffer(jsonValue))
data, err := ioutil.ReadAll(response.Body)
err = json.Unmarshal(data, &pdatar)
mdatar := make(models.JSON)
mdatar["ID"] = pdatar["id"]
mdatar["Name"] = pdatar["name"]
fmt.Println(mdatar) //This is how it is coming map[ID:[877,235], Name:[FCU, GHP]]
/*Another attempt
var temp models.Arr
json.Unmarshal(data, &temp)
fmt.Println(temp) ---- returning null
*/
return mdatar, nil
}
func (c Controller) GetSingle(pdata models.Single) (models.JSON, error) {
mdata := make(models.JSON)
mdata["group"] = pdata.Group
jsonValue, err := json.Marshal(mdata)
pdatar, err := SendToServer(jsonValue, "func_info")
return pdatar, nil
// json.NewEncoder(w).Encode(pdatar) //sending this to my main function
}
//model.go
type JSON map[string]interface{}
type Single struct {
ID int `json:"id"`
Name string `json:"name"`
}
type Data []Single
type Arr [][]string
I have a response from my API in a format
{
"id":[877,235,312,429],
"name" ["FCU","GHP","c","d"],
"group":["x","x","y","z"]
}
With Current Code I am receiving a response
{"id":[877 235], "name": ["FCU" "GHP"]
Though I am expecting a response
{
"data":
[
{"id": 877
"name" : "FCU"
}
{"id": 235
"name": "GHP"
}
]
}
Your mdatarr doesn't change the format any, so this result makes sense.
If the data received from the server is in the format:
{
"id": [877,235,312,429],
"name" ["FCU","GHP","c","d"],
"group": ["x","x","y","z"]
}
then you will need translate it. Ideally you'd fix the server so that it sends data in the format:
{
{
"id": 877,
"name": "FCU",
"group": "x",
},
...
}
If the server could send something like the above, then you could simply unmarshal it into a models.Data object.
If that is not an option, and you really need to do the translation client-side, then you'll need a for loop that does something like this:
ids := pdatarr["id"]
names := pdatarr["name"]
...
if len(ids) != len(names) {
return nil, errors.New("Invalid input format")
}
var mdatar models.Data
for i := range(ids) {
mdatar = append(mdatar, models.Single{ids[i], names[i], ...})
}
return models.JSON{"data": mdatar}, nil

unmarshal json array of records with inner arrays (all integers) [duplicate]

My input json data is this (cannot be changed, from an external resource):
[{
"Url": "test.url",
"Name": "testname"
},{
"FormName": "Test - 2018",
"FormNumber": 43,
"FormSlug": "test-2018"
}]
I have two structs that will always match the data within the array:
type UrlData struct{
"Url" string `json:Url`
"Name" string `json:Name`
}
type FormData struct{
"FormName" string `json:FormName`
"FormNumber" string `json:FormNumber`
"FormSlug" string `json:FormSlug`
}
Obviously the code below will not work, but is it possible at the top level (or otherwise) to declare something like this:
type ParallelData [
urlData UrlData
formData FormData
]
Use a two step process for unmarshaling. First, unmarshal a list of arbitrary JSON, then unmarshal the first and second element of that list into their respective types.
You can implement that logic in a method called UnmarshalJSON, thus implementing the json.Unmarshaler interface. This will give you the compound type you are looking for:
type ParallelData struct {
UrlData UrlData
FormData FormData
}
// UnmarshalJSON implements json.Unmarshaler.
func (p *ParallelData) UnmarshalJSON(b []byte) error {
var records []json.RawMessage
if err := json.Unmarshal(b, &records); err != nil {
return err
}
if len(records) < 2 {
return errors.New("short JSON array")
}
if err := json.Unmarshal(records[0], &p.UrlData); err != nil {
return err
}
if err := json.Unmarshal(records[1], &p.FormData); err != nil {
return err
}
return nil
}
Try it on the playground: https://play.golang.org/p/QMn_rbJj-P-
I think Answer of Peter is awesome.
Option 1:
type ParallelData [
urlData UrlData
formData FormData
]
if you need above structure then you can define it as
type UrlData struct {
Url string `json:"Url,omitempty"`
Name string `json:"Name,omitempty"`
}
type FormData struct {
FormName string `json:"FormName,omitempty"`
FormNumber string `json:"FormNumber,omitempty"`
FormSlug string `json:"FormSlug,omitempty"`
}
type ParallelData struct {
UrlData UrlData `json:"UrlData,omitempty"`
FormData FormData `json:"FormData,omitempty"`
}
In this case, your json will look like
[
{
"UrlData":{
"Url":"test.url",
"Name":"testname"
}
},
{
"FormData":{
"FormName":"Test - 2018",
"FormNumber":"43",
"FormSlug":"test-2018"
}
}
]
Option 2:
You've provide following json:
[
{
"Url":"test.url",
"Name":"testname"
},
{
"FormName":"Test - 2018",
"FormNumber":43,
"FormSlug":"test-2018"
}
]
If your json really look like, then you can use following struct
type UrlData struct {
Url string `json:Url`
Name string `json:Name`
}
type FormData struct {
FormName string `json:FormName`
FormNumber int `json:FormNumber`
FormSlug string `json:FormSlug`
}
type ParallelData struct {
UrlData
FormData
}
For both options, you can Unmarshall your json like this
var parallelData []ParallelData
err := json.Unmarshal([]byte(str), &parallelData)
if err != nil {
panic(err)
}
fmt.Println(parallelData)
See option 1 in playground
See option 2 in playground
You can unmarshal into a map[string]interface{} for example:
type ParallelData map[string]interface{}
func main() {
textBytes := []byte(`[
{
"Url": "test.url",
"Name": "testname"
},
{
"FormName": "Test - 2018",
"FormNumber": 43,
"FormSlug": "test-2018"
}]`)
var acc []ParallelData
json.Unmarshal(textBytes, &acc)
fmt.Printf("%+v", acc)
}
Output:
=> [map[Url:test.url Name:testname] map[FormName:Test - 2018 FormNumber:43 FormSlug:test-2018]]
Playground

Unmarshal 2 different structs in a slice

My input json data is this (cannot be changed, from an external resource):
[{
"Url": "test.url",
"Name": "testname"
},{
"FormName": "Test - 2018",
"FormNumber": 43,
"FormSlug": "test-2018"
}]
I have two structs that will always match the data within the array:
type UrlData struct{
"Url" string `json:Url`
"Name" string `json:Name`
}
type FormData struct{
"FormName" string `json:FormName`
"FormNumber" string `json:FormNumber`
"FormSlug" string `json:FormSlug`
}
Obviously the code below will not work, but is it possible at the top level (or otherwise) to declare something like this:
type ParallelData [
urlData UrlData
formData FormData
]
Use a two step process for unmarshaling. First, unmarshal a list of arbitrary JSON, then unmarshal the first and second element of that list into their respective types.
You can implement that logic in a method called UnmarshalJSON, thus implementing the json.Unmarshaler interface. This will give you the compound type you are looking for:
type ParallelData struct {
UrlData UrlData
FormData FormData
}
// UnmarshalJSON implements json.Unmarshaler.
func (p *ParallelData) UnmarshalJSON(b []byte) error {
var records []json.RawMessage
if err := json.Unmarshal(b, &records); err != nil {
return err
}
if len(records) < 2 {
return errors.New("short JSON array")
}
if err := json.Unmarshal(records[0], &p.UrlData); err != nil {
return err
}
if err := json.Unmarshal(records[1], &p.FormData); err != nil {
return err
}
return nil
}
Try it on the playground: https://play.golang.org/p/QMn_rbJj-P-
I think Answer of Peter is awesome.
Option 1:
type ParallelData [
urlData UrlData
formData FormData
]
if you need above structure then you can define it as
type UrlData struct {
Url string `json:"Url,omitempty"`
Name string `json:"Name,omitempty"`
}
type FormData struct {
FormName string `json:"FormName,omitempty"`
FormNumber string `json:"FormNumber,omitempty"`
FormSlug string `json:"FormSlug,omitempty"`
}
type ParallelData struct {
UrlData UrlData `json:"UrlData,omitempty"`
FormData FormData `json:"FormData,omitempty"`
}
In this case, your json will look like
[
{
"UrlData":{
"Url":"test.url",
"Name":"testname"
}
},
{
"FormData":{
"FormName":"Test - 2018",
"FormNumber":"43",
"FormSlug":"test-2018"
}
}
]
Option 2:
You've provide following json:
[
{
"Url":"test.url",
"Name":"testname"
},
{
"FormName":"Test - 2018",
"FormNumber":43,
"FormSlug":"test-2018"
}
]
If your json really look like, then you can use following struct
type UrlData struct {
Url string `json:Url`
Name string `json:Name`
}
type FormData struct {
FormName string `json:FormName`
FormNumber int `json:FormNumber`
FormSlug string `json:FormSlug`
}
type ParallelData struct {
UrlData
FormData
}
For both options, you can Unmarshall your json like this
var parallelData []ParallelData
err := json.Unmarshal([]byte(str), &parallelData)
if err != nil {
panic(err)
}
fmt.Println(parallelData)
See option 1 in playground
See option 2 in playground
You can unmarshal into a map[string]interface{} for example:
type ParallelData map[string]interface{}
func main() {
textBytes := []byte(`[
{
"Url": "test.url",
"Name": "testname"
},
{
"FormName": "Test - 2018",
"FormNumber": 43,
"FormSlug": "test-2018"
}]`)
var acc []ParallelData
json.Unmarshal(textBytes, &acc)
fmt.Printf("%+v", acc)
}
Output:
=> [map[Url:test.url Name:testname] map[FormName:Test - 2018 FormNumber:43 FormSlug:test-2018]]
Playground

Convert json single element arrays to strings

In Go I have to parse this json:
{
"response": [
{
"message": [
"hello world"
],
"misc": [
{
"timestamp": [
"2017-06-28T05:52:39.347Z"
],
"server": [
"server-0101"
]
}
]
}
]
}
I'd like to get an object in Go that doesn't include all the unnecessary arrays of with a single string. The source json will never have more than one string in each array.
So the end result that I'd like to get would be this json:
{
"response": {
"message": "hello world",
"misc": {
"timestamp": "2017-06-28T05:52:39.347Z",
"server": "server-0101"
}
}
}
Or an equivalent object in Go.
Right now I have to use Response[0].Misc[0].Timestamp[0] to access the data which seems weird.
You can override the default behaviour of json.Marshal / json.Unmarshal methods for a struct, by defining its own MarshalJSON or UnmarshalJSON properly.
Here there is an excerpt for the code of a simplified version of the struct you need to decode.
type Response struct {
Message string `json:"message"`
}
// UnmarshalJSON overrides the default behaviour for JSON unmarshal method.
func (r *Response) UnmarshalJSON(data []byte) error {
auxResponse := &struct {
Message []string `json:"message"`
}{}
if err := json.Unmarshal(data, &auxResponse); err != nil {
return err
}
// Consider to add some checks on array length :)
r.Message = auxResponse.Message[0]
return nil
}
You can access the full working example here.
I suggest you to read this interesting article about custom JSON encode/decode with golang.
I'd like to get an object in Go that doesn't include all the unnecessary arrays of with a single string.
The hard way: Parse the JSON by hand (write our own parser).
The sensible way: Unmarshal via package encoding/json into some Go type matching the JSON or into some generic interface{} and copy the pieces into a different, simpler Go type afterwards.
Creating your own unmarshaller is probably best, but this is a quick way to simulate what you want to achieve.
package main
import (
"encoding/json"
"fmt"
)
// JSON ...
var JSON = `{
"response": [
{
"message": [
"hello world"
],
"misc": [
{
"timestamp": [
"2017-06-28T05:52:39.347Z"
],
"server": [
"server-0101"
]
}
]
}
]
}
`
type rawObject struct {
Response []struct {
Message []string `json:"message"`
Misc []interface{} `json:"misc"`
} `json:"response"`
}
type clean struct {
Message string `json:"message"`
Misc map[string]interface{} `json:"misc"`
}
func main() {
var o rawObject
var c clean
// init map
c.Misc = make(map[string]interface{})
// unmarshall the raw data
json.Unmarshal([]byte(JSON), &o)
for _, res := range o.Response { // I assume there should only be one response, don't know why this is wrapped as an array
// assume message is not really an array
c.Message = res.Message[0]
// convert []interface to map[string]interface
for _, m := range res.Misc {
for k, v := range m.(map[string]interface{}) {
c.Misc[k] = v
}
}
}
fmt.Printf("%+v\n", c)
}
What i don't like about this answer is that it isn't very reusable..so a function should probably be made and more error checking (part of creating a custom unmarshaller). If this were used in heavy production it might run into some memory issues, as I have to create a raw object to create a clean object.. but as a one off script it does the job. I my clean struct doesn't add response as a type because i find it to be redundant.

Resources