json unmarshal in gloang for complex json data - json

i want to json unmarshal following data in golang :
{
RESPONSE : {
CODE : "123"
NEW_RESPONSE :{
0:[
{
key1:val1,
key2:val2
},
{
key3:val3,
key4:val4
}
]
1:[
{
key5:val5,
key6:val6,
key7:val7
},
{
key31:val31,
key42:val42
}
]
2:{
key8:val8,
key9:val9,
key1-:val10
}
3:{}
}
}
}
I want to access every key of this data. What i was trying is
type testData struct{
Code string `json:"CODE"`
NewResponse map[string]interface{} `json:"NEW_RESPONSE"`}
type GetData struct{
TestResponse testData `json:"RESPONSE"`}
After this I am not able to furthur use "NewResponse". Need help. Thanks in advance.

You can access elements of NewResponse using the key:
elem:=NewResponse["0"]
Looking at the input document, elem is an array of objects. The rest of the code will use type assertions:
if arr, ok:=elem.([]interface{}); ok {
// arr is a JSON array
objElem:=arr[0].(map[string]interface{})
for key,value:=range objElem {
// key: "key1"
// value: "val1"
val:=value.(string)
...
}
} else if obj, ok:=elem.(map[string]interface{}); ok {
// obj is a JSON object
for key, val:=range obj {
// key: "key1"
value:=val.(string)
}
}

Plz validate your json format
this may solve your purpose.
package main
import (
"encoding/json"
"fmt"
)
func main() {
Json := `{
"RESPONSE" : {
"CODE" : "123",
"NEW_RESPONSE" :{
"0":{
"s" : 1,
"s1" :2,
"s3": 3
}
}
}
}`
// Declared an empty interface
var result map[string]interface{}
// Unmarshal or Decode the JSON to the interface.
err := json.Unmarshal([]byte(Json), &result)
if err != nil{
fmt.Println("Err : ",err)
}else{
fmt.Println(result)
}
}

Related

Trying to get 2 integers out of a JSON subsection

I'm using the VirusTotal HTTP API in Golang to get the votes on an URL, both malicious and harmless.
I want to get them using structs, and then unmarshaling the URL using data from these structs. But when I try that, this error shows up:
cannot convert "harmless" (untyped string constant) to int
The code I am currently using is:
type Votes struct {
harmless int
malicious int
}
type Attributes struct {
votes []Votes `json:"total_votes"`
}
type data struct {
attributes []Attributes `json:"attributes"`
}
type jsonstruct struct {
data []data `json:"data"`
}
var printdata jsonstruct
fmt.Println(resp)
json.Unmarshal([]byte(body), &printdata)
fmt.Println(printdata.data[0].attributes[0].votes["harmless"])
And the part of the JSON that I want to get is:
{
"data": {
"attributes": {
"last_modification_date": 1642534694,
"last_http_response_cookies": {
"1P_JAR": "2022-01-18-19",
"NID": "511=drq8-0Gwl0gpw2D-iyZhxrizpE--UMOyc_bO381XXkxknypvl_IETvsxRw3p8kMlBtiYEuSbASKK1wHirmgxce79kgzGMg9MryT0PnHox6kWbmEQTe2vsv_HtVZDFDXiLt4HKpcyDczOT8c_OK8bPb_P-f8rbIXJu_xrA0Ce4lw",
"SameSite": "none"
},
"times_submitted": 82289,
"total_votes": {
"harmless": 54,
"malicious": 18
},
As you can see, I want to get the contents of the subsection total_votes, which are integers harmless and malicious. In short, how can I get them without getting the error about them being untyped strings?
You need to define valid data structure that matches json structure. And after Unmarshal you can access votes fields as res.Data.Attributes.TotalVotes.Harmless . For example (https://go.dev/play/p/YCtV1u-KF7Y):
package main
import (
"encoding/json"
"fmt"
"log"
)
type Result struct {
Data struct {
Attributes struct {
LastHTTPResponseCookies struct {
OnePJAR string `json:"1P_JAR"`
Nid string `json:"NID"`
SameSite string `json:"SameSite"`
} `json:"last_http_response_cookies"`
LastModificationDate float64 `json:"last_modification_date"`
TimesSubmitted float64 `json:"times_submitted"`
TotalVotes struct {
Harmless float64 `json:"harmless"`
Malicious float64 `json:"malicious"`
} `json:"total_votes"`
} `json:"attributes"`
} `json:"data"`
}
var input = `{
"data": {
"attributes": {
"last_modification_date": 1642534694,
"last_http_response_cookies": {
"1P_JAR": "2022-01-18-19",
"NID": "pcyDczOT8c_OK8bPb_P-f8rbIXJu_xrA0Ce4lw",
"SameSite": "none"
},
"times_submitted": 82289,
"total_votes": {
"harmless": 54,
"malicious": 18
}
}
}
}
`
func main() {
var res Result
if err := json.Unmarshal([]byte(input), &res); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v", res.Data.Attributes.TotalVotes.Harmless)
}

Encoding struct to json Go

I have an issue encoding struct to json my code is
type MainStructure struct {
Text string json:"text,omitempty"
Array []TestArray json:"test_array,omitmepty"
}
type TestArray struct {
ArrayText string json:"array_text,omitempty"
}
func main() {
Test := MainStructure{
Text: "test",
Array: [
{
ArrayText: "test1"
},
{
ArrayText: "test2"
}
]
}
body := new(bytes.Buffer)
json.NewEncoder(body).Encode(&Test)
fmt.Println(string([]byte(body)))
}
the wanted result should be
{
"text": "test",
"test_array": [
{
"array_text": "test1"
},
{
"array_text": "test2"
}
]
}
I do not mind if it's "Marshal" or "encoding/json"
To encode a struct to JSON string, there are three ways that provided by standard library :
Using Encoder which convert struct to JSON string, then write it to io.Writer. This one usually used if you want to send JSON data as HTTP request, or saving the JSON string to a file.
Using Marshal which simply convert struct to bytes, which can be easily converted to string.
Using MarshalIndent which works like Marshal, except it's also prettify the output. This is what you want for your problem right now.
To compare between those three methods, you can use this code (Go Playground):
package main
import (
"bytes"
"encoding/json"
"fmt"
)
type MainStructure struct {
Text string `json:"text,omitempty"`
Array []TestArray `json:"test_array,omitempty"`
}
type TestArray struct {
ArrayText string `json:"array_text,omitempty"`
}
func main() {
Test := MainStructure{
Text: "test",
Array: []TestArray{
{ArrayText: "test1"},
{ArrayText: "test2"},
},
}
// Using marshal indent
btResult, _ := json.MarshalIndent(&Test, "", " ")
fmt.Println("Using Marshal Indent:\n" + string(btResult))
// Using marshal
btResult, _ = json.Marshal(&Test)
fmt.Println("\nUsing Marshal:\n" + string(btResult))
// Using encoder
var buffer bytes.Buffer
json.NewEncoder(&buffer).Encode(&Test)
fmt.Println("\nUsing Encoder:\n" + buffer.String())
}
The output will look like this :
Using Marshal Indent:
{
"text": "test",
"test_array": [
{
"array_text": "test1"
},
{
"array_text": "test2"
}
]
}
Using Marshal:
{"text":"test","test_array":[{"array_text":"test1"},{"array_text":"test2"}]}
Using Encoder:
{"text":"test","test_array":[{"array_text":"test1"},{"array_text":"test2"}]}
First of all I think you are going wrong on how to create a struct in go, as you can easily convert them to json.
You should be first making a proper struct then do json.marshal(Test) to convert it to proper json like:
package main
import (
"encoding/json"
"fmt"
)
func main() {
type TestArray struct {
ArrayText string `json:"array_text,omitempty"`
}
type MainStructure struct {
Text string `json:"text,omitempty"`
Array []TestArray `json:"test_array,omitmepty"`
}
Test := MainStructure{
Text: "test",
Array: []TestArray{
TestArray{ArrayText: "test1"},
TestArray{ArrayText: "test2"},
}}
bytes, err := json.Marshal(Test)
if err != nil {
fmt.Println("eror marshalling")
} else {
fmt.Println(string(bytes))
}
}
Check this out on play.golang.org
I could not get the point you wanted to use bytes.Buffer if your objective is just to put the result into the console. Assuming the point is:
Create a struct instance (corresponding to a JSON object)
Emit it in the screen
The following code can help you:
package main
import "encoding/json"
import "fmt"
type MainStructure struct {
Text string `json:"text,omitempty"`
Array []TestArray `json:"test_array,omitmepty"`
}
type TestArray struct {
ArrayText string `json:"array_text,omitempty"`
}
func main() {
Test := MainStructure{
Text: "test",
Array: []TestArray{
TestArray{"test1"},
TestArray{"test2"},
},
}
res, _ := json.MarshalIndent(Test, "", "\t")
fmt.Println(string(res))
}
json.MarshalIndent is used to make result pretty-formatted, if you bother it.

How do I pass array of key,value pairs to golang slice of struct through json

I am writing a simple post api request. I am able to parse the JSON into golang structs upto the peername json object. I do not know the correct syntax to populate a golang slice of a struct by passing values through the JSON body of the api.
I am trying to parse JSON body sent through an api. This is the sample body request -
{
"type":"string",
"name":"string",
"organization":{
"orgID":"1",
"orgName":"string",
"peer":{
"peerID":"1",
"peerName":"string"
},
"attributes":[
["slide0001.html", "Looking Ahead"],
["slide0008.html", "Forecast"],
["slide0021.html", "Summary"]
]
}
} "peerName":"string"
},
"attributes":["name":"string":"value":true]
}
}
And this is my sample golang structs.
//Identity ...
type Identity struct {
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Organization *Organization `json:"organization,omitempty"`
}
//Organization ....
type Organization struct {
OrgID string `json:"orgID,omitempty"`
OrgName string `json:"orgName,omitempty"`
Peer *Peer `json:"peer,omitempty"`
Attributes *Attributes `json:"attributes"`
}
//Peer ...
type Peer struct {
PeerID string `json:"peerID,omitempty"`
PeerName string `json:"peerName,omitempty"`
}
//Attributes ...
type Attributes []struct {
Name string `json:"name"`
Value bool `json:"value"`
}
Finally figured out the correct syntax. We have to pass an array of structs through JSON.
{
"type":"string",
"name":"string",
"organization":
{
"orgID":"1",
"orgName":"string",
"peer":
{
"peerID":"1",
"peerName":"string"
},
"attributes":
[
{"slide0001.html": "Looking Ahead"},
{"slide0008.html": "Forecast"},
{"slide0021.html": "Summary"}
]
}
}
you can do whatever you want in a UnmarshalJSON Function.
i made an example in playground. https://play.golang.org/p/WY6OCR8K3Co
you can get output: {A:[{Name:slide0001.html Value:Looking Ahead} {Name:slide0008.html Value:Forecast} {Name:slide0021.html Value:Summary}]}
var (
jso = []byte(`
{
"attributes":
[
{"slide0001.html": "Looking Ahead"},
{"slide0008.html": "Forecast"},
{"slide0021.html": "Summary"}
]
}`)
)
type B struct {
A As `json:"attributes"`
}
type As []A
type A struct {
Name string
Value string
}
func (as *As) UnmarshalJSON(data []byte) error {
var attr []interface{}
if err := json.Unmarshal(data, &attr); err != nil {
return err
}
if len(attr) > 0 {
newAs := make([]A, len(attr))
// i := 0
for i, val := range attr {
if kv, ok := val.(map[string]interface{}); ok && len(kv) > 0 {
for k, v := range kv {
a := A{
Name: k,
Value: v.(string),
}
newAs[i] = a
i++
break
}
}
}
*as = newAs
}
return nil
}

Unmarshal with changing JSON attribute

I have a JSON object whose details can contain different types of JSON objects, the rest of the JSON remains the same, in such a case how can I have a single struct in Golang to handle both types of JSON
JSON 1:
{
"field1":"",
"field2":"",
"field3":"",
"field4":"",
"field5":"",
"field6":"",
"field7":"",
"details":{
"detail1":"",
"detail2":[
{
"arr1":"",
"arr2":{
"id":"",
"name":""
},
"list":[
{
"id":"",
"version":1,
"name":""
}
]
}
]
},
"user":{
"id":"",
"name":""
}
}
JSON 2:
{
"field1":"",
"field2":"",
"field3":"",
"field4":"",
"field5":"",
"field6":"",
"field7":"",
"details":{
"anotherdetail1":"",
"anotherdetail2":[
{
"arr7":"",
"arr8":{
"id":"",
"name":""
},
"arr10":{
}
}
]
},
"user":{
"id":"",
"name":""
}
}
My goal is to use a single struct for both these JSON objects. In a language like Java I would create a Parent Class which resembles details in a generic way and have 2 child classes to resemble the type of details that vary and during runtime I would create an object of a child type and assign it to the Parent. I am unsure how this is done in Go.
I am not sure you can have a single struct unless you are ok with a string interface map, but You can prevent the details from being decoded by setting them as a json.RawMessage type int he struct. You can then decode the unknown-typed json data by attempting to decode it into one type, if that returns an error then you try with the next type.
Here is some code, that should give you a better idea to what I am talking about.
https://play.golang.org/p/06owmiJXNaO
package main
import (
"encoding/json"
"fmt"
)
const json1 = `{"name": "foo", "details":[1, 2, 3]}`
const json2 = `{"name": "foo", "details":{"a": [1, 2, 3]}}`
type data struct {
Name string `json:"name"`
Details json.RawMessage `json:"details"`
}
type detailsone []int
type detailstwo struct {
A []int `json:"a"`
}
func main() {
var d1, d2 data
json.Unmarshal([]byte(json1), &d1)
json.Unmarshal([]byte(json2), &d2)
fmt.Printf("%+v\n", d1)
fmt.Printf("%+v\n", d2)
var err error
var b1 detailsone
var b2 detailstwo
// json1
err = json.Unmarshal([]byte(d1.Details), &b1)
if err == nil {
fmt.Printf("d1 is an []int: %+v\n", b1)
}
err = json.Unmarshal([]byte(d1.Details), &b2)
if err == nil {
fmt.Printf("d1 is an detailstwo struct: %+v\n", b2)
}
// json2
err = json.Unmarshal([]byte(d2.Details), &b1)
if err == nil {
fmt.Printf("d2 is an []int: %+v\n", b1)
}
err = json.Unmarshal([]byte(d2.Details), &b2)
if err == nil {
fmt.Printf("d2 is an detailstwo struct: %+v\n", b2)
}
}
type Base struct {
Data map[string]interface{}
Details struct {
*D1
*D2
} `json:"details"
}
type D1 struct {
Detail1 string
Detail2 string
}
type D2 struct {
AnotherDetail1 string
AnotherDetail2 string
}
you can find filled struct by comparing them with nil

Mapping JSON returned by REST API containing dynamic keys to a struct in Golang

I'm calling a REST API from my Go program which takes n number of hotel ids in the request and returns their data as a JSON. The response is like the following when say I pass 2 ids in the request, 1018089108070373346 and 2017089208070373346 :
{
"data": {
"1018089108070373346": {
"name": "A Nice Hotel",
"success": true
},
"2017089208070373346": {
"name": "Another Nice Hotel",
"success": true
}
}
}
Since I'm new to Golang I using a JSON Go tool available at http://mholt.github.io/json-to-go/ to get the struct representation for the above response. What I get is:
type Autogenerated struct {
Data struct {
Num1017089108070373346 struct {
Name string `json:"name"`
Success bool `json:"success"`
} `json:"1017089108070373346"`
Num2017089208070373346 struct {
Name string `json:"name"`
Success bool `json:"success"`
} `json:"2017089208070373346"`
} `json:"data"`
}
I cannot use the above struct because the actual id values and the number of ids I pass can be different each time, the JSON returned will have different keys. How can this situation be mapped to a struct ?
Thanks
Use a map:
type Item struct {
Name string `json:"name"`
Success bool `json:"success"`
}
type Response struct {
Data map[string]Item `json:"data"`
}
Run it on the playground
Here is some sample code that utilizes Mellow Marmots answer and shows how to iterate over the items in the response.
test.json
{
"data": {
"1018089108070373346": {
"name": "A Nice Hotel",
"success": true
},
"2017089208070373346": {
"name": "Another Nice Hotel",
"success": true
}
}
}
test.go
package main
import (
"encoding/json"
"fmt"
"os"
)
// Item struct
type Item struct {
Name string `json:"name"`
Success bool `json:"success"`
}
// Response struct
type Response struct {
Data map[string]Item `json:"data"`
}
func main() {
jsonFile, err := os.Open("test.json")
if err != nil {
fmt.Println("Error opening test file\n", err.Error())
return
}
jsonParser := json.NewDecoder(jsonFile)
var filedata Response
if err = jsonParser.Decode(&filedata); err != nil {
fmt.Println("Error while reading test file.\n", err.Error())
return
}
for key, value := range filedata.Data {
fmt.Println(key, value.Name, value.Success)
}
}
Which outputs:
1018089108070373346 A Nice Hotel true
2017089208070373346 Another Nice Hotel true