Parse stringified JSON - json

I'm trying to parse stringified JSON with Go, but I cannot find anything that explains how do to efficient parsing.
Example JSON:
{
"messages":"<ul class=\"messages\"><li class=\"success-msg\"><ul><li><span>Item succcessfully added<\/span><\/li><\/ul><\/li><\/ul>",
"app_cart":"[]",
"addcartrows":"[{\"productId\":\"1675688\",\"quantity\":1,\"unitPrice\":\"290.00\",\"currency\":\"EUR\",\"sku\":\"P00525485-3\"}]",
"minicart_content":"<ul class=\"checkout-types minicart\">\n
<li>",
"cart_qty":"1",
"added_product_json":"{\"id\":\"1675695\",\"size\":\"40\"}"
}
I usually parse json by casting it to a struct. like this:
type AutoGenerated struct {
Messages string `json:"messages"`
AppCart string `json:"app_cart"`
Addcartrows string `json:"addcartrows"`
MinicartContent string `json:"minicart_content"`
CartQty string `json:"cart_qty"`
AddedProductJSON string `json:"added_product_json"`
}
var j AutoGenerated
if err = json.Unmarshal(body, &AutoGenerated); err != nil {
fmt.Println(err) // json: cannot unmarshal string into Go struct field AutoGenerated.added_product_json
}
However I do not know how to correctly parse this type of response.
Any help?

do it in two steps.
package main
import (
"encoding/json"
"fmt"
)
func main() {
type AutoGenerated struct {
Messages string `json:"messages"`
AppCart string `json:"app_cart"`
Addcartrows string `json:"addcartrows"`
MinicartContent string `json:"minicart_content"`
CartQty string `json:"cart_qty"`
AddedProductJSON string `json:"added_product_json"`
}
type addedProduct struct {
ID string `json:"id"`
Size string `json:"size"`
}
type productRow struct {
ProductID string `json:"productId"`
Quantity int `json:"quantity"`
UnitPrice string `json:"unitPrice"`
Currency string `json:"currency"`
SKU string `json:"sku"`
}
var j AutoGenerated
body := []byte(`{
"messages":"<ul class=\"messages\"><li class=\"success-msg\"><ul><li><span>Item succcessfully added<\/span><\/li><\/ul><\/li><\/ul>",
"app_cart":"[]",
"addcartrows":"[{\"productId\":\"1675688\",\"quantity\":1,\"unitPrice\":\"290.00\",\"currency\":\"EUR\",\"sku\":\"P00525485-3\"}]",
"minicart_content":"<ul class=\"checkout-types minicart\">\n<li>",
"cart_qty":"1",
"added_product_json":"{\"id\":\"1675695\",\"size\":\"40\"}"
}`)
if err := json.Unmarshal(body, &j); err != nil {
panic(err)
}
var k []productRow
if err := json.Unmarshal([]byte(j.Addcartrows), &k); err != nil {
panic(err)
}
var u addedProduct
if err := json.Unmarshal([]byte(j.AddedProductJSON), &u); err != nil {
panic(err)
}
fmt.Printf("%#v\n\n", j)
fmt.Printf("%#v\n\n", k)
fmt.Printf("%#v\n\n", u)
}

Assuming the json you have added has a formatting issue for value of "minicart_content" , below should help -
package main
import (
"fmt"
"encoding/json"
)
var myjson string = `{
"messages": "<ul class=\"messages\"><li class=\"success-msg\"><ul><li><span>Item succcessfully added<\/span><\/li><\/ul><\/li><\/ul>",
"app_cart": "[]",
"addcartrows": "[{\"productId\":\"1675688\",\"quantity\":1,\"unitPrice\":\"290.00\",\"currency\":\"EUR\",\"sku\":\"P00525485-3\"}]",
"minicart_content": "<ul class=\"checkout-types minicart\">\n <li > ",
"cart_qty": "1",
"added_product_json": "{\"id\":\"1675695\",\"size\":\"40\"}"
}`
type AutoGenerated struct {
Messages string `json:"messages"`
AppCart string `json:"app_cart"`
Addcartrows string `json:"addcartrows"`
MinicartContent string `json:"minicart_content"`
CartQty string `json:"cart_qty"`
AddedProductJSON string `json:"added_product_json"`
}
func main() {
var j AutoGenerated
if err := json.Unmarshal([]byte(myjson), &j); err != nil {
fmt.Println(err)
}
fmt.Println(j.AddedProductJSON)
}

Related

function to print from from a Json each item using a for loop golang

package main
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
)
type Response struct {
Status string `json:"status"`
Message string `json:"message"`
Result []struct {
BlockNumber string `json:"blockNumber"`
TimeStamp string `json:"timeStamp"`
Hash string `json:"hash"`
Nonce string `json:"nonce"`
BlockHash string `json:"blockHash"`
TransactionIndex string `json:"transactionIndex"`
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
IsError string `json:"isError"`
TxreceiptStatus string `json:"txreceipt_status"`
Input string `json:"input"`
ContractAddress string `json:"contractAddress"`
CumulativeGasUsed string `json:"cumulativeGasUsed"`
GasUsed string `json:"gasUsed"`
Confirmations string `json:"confirmations"`
} `json:"result"`
}
func getapi(wallet string) ([]byte, error) {
res, err := http.Get("https://api.bscscan.com/api?module=account&action=txlist&address=" + wallet + "&startblock=0&endblock=99999999&sort=asc&apikey=5Q4SS1XHV95SIPSCKK1FKCPGJSMRM2EI1K")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
return ioutil.ReadAll(res.Body)
}
func j_unm(body []byte) Response {
var r Response
err := json.Unmarshal(body, &r)
if err != nil {
log.Println("Error unmarshalling json data:", err)
}
return r
}
func printitem(r Response, jitem string) []string {
item := []string{}
for _, p := range r.Result {
item = append(item, jitem+":"+p.jitem)
}
return item
}
package main
import "fmt"
func main() {
gettrx, _ := getapi("0xf287E9f40f96C0cbAEAdD29Cf22E6CF5cC66030b")
fmt.Println(printitem(j_unm(gettrx), "BlockNumber"))
}
I want to pass as jitem as variable. I got the following error.
jitem is define as string, could be BlockNumber or TimeStamp
p.jitem undefined (type struct{BlockNumber string "json:\"blockNumber\""; TimeStamp string "json:\"timeStamp\""; Hash string "json:\"hash\""; Nonce string "json:\"nonce\""; BlockHash string "json:\"blockHash\""; TransactionIndex string "json:\"transactionIndex\""; From string "json:\"from\""; To string "json:\"to\""; Value string "json:\"value\""; Gas string "json:\"gas\""; GasPrice string "json:\"gasPrice\""; IsError string "json:\"isError\""; TxreceiptStatus string "json:\"txreceipt_status\""; Input string "json:\"input\""; ContractAddress string "json:\"contractAddress\""; CumulativeGasUsed string "json:\"cumulativeGasUsed\""; GasUsed string "json:\"gasUsed\""; Confirmations string "json:\"confirmations\""} has no field or method jitem)compilerMissingFieldOrMethod
is p.jitem is string? if is this type is convertible to string,then use string(p.jitem)
func printitem(r Response, jItem string) []string {
//item := []string{}
items:= make([]string,0)
for _, p := range r.Result {
items = append(items, jItem+":"+ string(p.jItem))
}
return items
do you want this?
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type Response struct {
Status string `json:"status"`
Message string `json:"message"`
Result []map[string]string `json:"result"`
}
func getapi(wallet string) ([]byte, error) {
res, err := http.Get("https://api.bscscan.com/api?module=account&action=txlist&address=" + wallet + "&startblock=0&endblock=99999999&sort=asc&apikey=5Q4SS1XHV95SIPSCKK1FKCPGJSMRM2EI1K")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
return ioutil.ReadAll(res.Body)
}
func j_unm(body []byte) Response {
var r Response
err := json.Unmarshal(body, &r)
if err != nil {
log.Println("Error unmarshalling json data:", err)
}
return r
}
func printitem(r Response, jitem string) []string {
item := []string{}
for _, p := range r.Result {
item = append(item, jitem+":"+p[jitem])
}
return item
}
func main() {
gettrx, _ := getapi("0xf287E9f40f96C0cbAEAdD29Cf22E6CF5cC66030b")
fmt.Println(printitem(j_unm(gettrx), "blockNumber"))
}

Golang json.Unmarshal is not working as expected

Im trying to unmarshal json response from vcenter rest api. when the response body is simply printed it looks like the o/p below
{"value":[{"memory_size_MiB":16384,"vm":"vm-10236","name":"Normal_Windows_192.168.1.10","power_state":"POWERED_OFF","cpu_count":8},{"memory_size_MiB":8192,"vm":"vm-10238","name":"Normal_Windows_192.168.1.11","power_state":"POWERED_OFF","cpu_count":4}]}
i have exported both struct and struct fields however the fields like memory_size_MiB, power_state,cpu_count is not being unmarshalled. when the struct is printed it looks like below:-
{Value:[{Mem:0 Vm:vm-10236 Name:Normal_Windows_192.168.1.10 Powerstat: Cpu:0} {Mem:0 Vm:vm-10238 Name:Normal_Windows_192.168.1.11 Powerstat: Cpu:0} {Mem:0 Vm:vm-10582 Name:Normal_Windows_192.168.1.12 Powerstat: Cpu:0}]}%
Below is my main.go
package main
import (
...
)
type SessionData struct {
VmwareApiSessionId string `json:"value"`
}
//{"memory_size_MiB":16384,"vm":"vm-10236","name":"Normal_Windows_192.168.19.100","power_state":"POWERED_OFF","cpu_count":8}
type Vm struct {
Mem int `json: "memory_size_MiB"`
Vm string `json: "vm"`
Name string `json: "name"`
Powerstat string `json: "power_state"`
Cpu int `json: "cpu_count"`
}
//{Value:[{Mem:0 Vm:vm-10236 Name:Normal_Windows_192.168.1.10 Powerstat: Cpu:0} {Mem:0 Vm:vm-10238 Name:Normal_Windows_192.168.1.11 Powerstat: Cpu:0} {Mem:0 Vm:vm-10582 Name:Normal_Windows_192.168.1.12 Powerstat: Cpu:0}]}
type ColVmList struct {
Value []Vm `json: "value"`
}
func getVmList(sessid string,cli *http.Client) ColVmList {
vms := ColVmList{}
req,err:=http.NewRequest("GET","https://sandbox.vmware.local/rest/vcenter/vm",nil)
req.Header.Add("vmware-api-session-id",sessid)
resp,err := cli.Do(req)
if err != nil {
log.Fatal("Error %s", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
err = json.Unmarshal([]byte(body),&vms)
if err != nil {
log.Fatal("error %s", err)
}
return vms
}
func main(){
//authpart
loginurl = "https://sandbox.vmware.local/rest/com/vmware/cis/session"
//login...
err = json.Unmarshal([]byte(string(body)),&sessVal)
if err != nil{
log.Fatal(err)
}
var allvmlist ColVmList
allvmlist = getVmList(sessVal.VmwareApiSessionId,&cli)
fmt.Printf("%v",allvmlist)
}
Your struct tags are not well formed. Remove the space between json: and the string "..." in the struct tags. i.e. it MUST be json:"..." not json: "...".
And the reason some fields are correctly unmarshaled even with not well-formed struct tags is because the fields' names match the json property names.
func main() {
data := []byte(`{"memory_size_MiB":16384}`)
var obj1 struct {
Mem int `json: "memory_size_MiB"`
}
if err := json.Unmarshal(data, &obj1); err != nil {
panic(err)
}
fmt.Println(obj1)
var obj2 struct {
Mem int `json:"memory_size_MiB"`
}
if err := json.Unmarshal(data, &obj2); err != nil {
panic(err)
}
fmt.Println(obj2)
}
https://go.dev/play/p/gUR5ed2n0D1

Map JSON array value to struct specific variable

Let's say I have this JSON structure:
{
"name":"repo",
"tags":["1.0","2.0","3.0"]
}
And I would like to map it to this Go struct:
type Repository struct {
Name string `json:"name"`
Tags []struct {
Tag string `json:"??"`
Sha256 string
}
}
How can I link the "tags" array JSON value to a struct field?
EDIT: The idea will be to access the tags array value like this
repository.Tags[0].Tag.
Implement json.Unmarshaler on a Tag type:
package main
import (
"encoding/json"
"log"
)
type Repository struct {
Name string
Tags []Tag
}
type Tag struct {
Tag string
Sha256 string
}
func (t *Tag) UnmarshalJSON(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
t.Tag = s
return nil
}
func main() {
b := []byte(`{ "name":"repo", "tags":["1.0","2.0","3.0"] }`)
var r Repository
err := json.Unmarshal(b, &r)
if err != nil {
log.Fatal(err)
}
log.Printf("%+v\n", r)
}
Try it on the playground: https://play.golang.org/p/ExwWhis0w0V
Marshaling back to JSON is left as an exercise for the reader.

Unmarshalling json to structure using json.RawMessage

I need to unmarshal json object which may have the following formats:
Format1:
{
"contactType": 2,
"value": "0123456789"
}
Format2:
{
"contactType": "MobileNumber",
"value": "0123456789"
}
The structure I'm using for unmarshalling is:-
type Contact struct {
ContactType int `json:"contactType"`
Value string `json:"value"`
}
But this works only for format 1. I don't want to change the datatype of ContactType but I want to accommodate the 2nd format as well. I heard about json.RawMarshal and tried using it.
type Contact struct {
ContactType int
Value string `json:"value"`
Type json.RawMessage `json:"contactType"`
}
type StringContact struct {
Type string `json:"contactType"`
}
type IntContact struct {
Type int `json:"contactType"`
}
This gets the unmarshalling done, but I'm unable to set the ContactType variable which depends on the type of json.RawMessage. How do I model my structure so that this problem gets solved?
You will need to do the unmarshalling yourself. There is a very good article that shows how to use the json.RawMessage right and a number of other solutions to this very problem, Like using interfaces, RawMessage, implemention your own unmarshal and decode functions etc.
You will find the article here: JSON decoding in GO by Attila Oláh
Note: Attila has made a few errors on his code examples.
I taken the liberty to put together (using some of the code from Attila) a working example using RawMessage to delay the unmarshaling so we can do it on our own version of the Decode func.
Link to GOLANG Playground
package main
import (
"fmt"
"encoding/json"
"io"
)
type Record struct {
AuthorRaw json.RawMessage `json:"author"`
Title string `json:"title"`
URL string `json:"url"`
Author Author
}
type Author struct {
ID uint64 `json:"id"`
Email string `json:"email"`
}
func Decode(r io.Reader) (x *Record, err error) {
x = new(Record)
if err = json.NewDecoder(r).Decode(x); err != nil {
return
}
if err = json.Unmarshal(x.AuthorRaw, &x.Author); err == nil {
return
}
var s string
if err = json.Unmarshal(x.AuthorRaw, &s); err == nil {
x.Author.Email = s
return
}
var n uint64
if err = json.Unmarshal(x.AuthorRaw, &n); err == nil {
x.Author.ID = n
}
return
}
func main() {
byt_1 := []byte(`{"author": 2,"title": "some things","url": "https://stackoverflow.com"}`)
byt_2 := []byte(`{"author": "Mad Scientist","title": "some things","url": "https://stackoverflow.com"}`)
var dat Record
if err := json.Unmarshal(byt_1, &dat); err != nil {
panic(err)
}
fmt.Printf("%#s\r\n", dat)
if err := json.Unmarshal(byt_2, &dat); err != nil {
panic(err)
}
fmt.Printf("%#s\r\n", dat)
}
Hope this helps.

go "encoding/json" : marshal json field

I have a PostgreSQL schema with json field's (DisplayInfo, and FormatInfo). Structure of this field's is dynamic.
I'can read and render it only as string (string type in render struct) :
[
{
"ID":9,
"Name":"120 №1",
"DisplayInfo":"{\"path\": \"http://path/to/img.png\"}",
"Format":{
"Code":"frame-120",
"Width":120,
"Height":60,
"FormatInfo":"[{\"name\": \"\\u0413\\u043b\\u0430\\u0432\\u043d\\u043e\\u0435 \\u0438\\u0437\\u043e\\u0431\\u0440\\u0430\\u0436\\u0435\\u043d\\u0438\\u0435\", \"field_type\": \"img\", \"key\": \"path\"}]"
},
"Weight":0.075,
"Application":8,
"Url":"//path/to/game",
"Referrer":""
}
]
but i want output field DisplayInfo as JSON object. How ?
My render code:
func renderJSON(w http.ResponseWriter, obj models.Model) {
js, err := json.Marshal(obj)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Write(js)
}
UPD 1 : Structure of this field's is dynamic. DisplayInfo may have 'path' field, or may not. They may have additional fields.
UPD 2. I wana output DisplayInfo and FormatInfo as json-object(not string), as part of whole object, like this:
[
{
"ID":9,
"Name":"120 №1",
"DisplayInfo":{"path": "http://path/to/img.png"},
"Format":{
"Code":"frame-120",
"Width":120,
"Height":60,
"FormatInfo":[{"name": "\\u0413\\u043b\\u0430\\u0432\\u043d\\u043e\\u0435 \\u0438\\u0437\\u043e\\u0431\\u0440\\u0430\\u0436\\u0435\\u043d\\u0438\\u0435", "field_type": "img", "key": "path"}]
},
"Weight":0.075,
"Application":8,
"Url":"//path/to/game",
"Referrer":""
}
]
UPD 3: Structures
Actual structure is :
type BannerSerializer struct {
ID int
Name string
DisplayInfo string
Format formatSerializer
Weight float32
Application int
Url string
Referrer string
}
Then i trying this structure:
type BannerSerializer struct {
ID int
Name string
DisplayInfo json.RawMessage
Format formatSerializer
Weight float32
Application int
Url string
Referrer string
}
DisplayInfo serialize as base64 string (or like base64, don't know)
Use a pointer to json.RawMessage:
type Data struct {
Obj *json.RawMessage
}
Playground: http://play.golang.org/p/Qq9IUBDLzJ.
Assuming you have access to change models.Model, you can create your own type with a custom Unmarshaler that just returns the raw string:
type JSONString string
func (s JSONString) MarshalJSON() ([]byte, error) {
return []byte(s), nil
}
Working example:
package main
import (
"encoding/json"
"fmt"
)
type JSONString string
func (s JSONString) MarshalJSON() ([]byte, error) {
return []byte(s), nil
}
type Model struct {
ID int
Name string
DisplayInfo JSONString
}
func main() {
data := []byte(`{
"ID":9,
"Name":"120 №1",
"DisplayInfo":"{\"path\": \"http://path/to/img.png\"}"
}`)
var obj Model
err := json.Unmarshal(data, &obj)
if err != nil {
panic(err)
}
// Here comes your code
js, err := json.Marshal(obj)
if err != nil {
panic(err)
}
fmt.Println(string(js))
}
Output:
{"ID":9,"Name":"120 №1","DisplayInfo":{"path":"http://path/to/img.png"}}
Playground: http://play.golang.org/p/6bcnuGjlU8
You'd have to unmarshal it, here's an example:
var data []*struct {
ID int
DisplayInfo string
}
if err := json.Unmarshal([]byte(j), &data); err != nil {
log.Fatal(err)
}
for _, d := range data {
var displayInfo struct{ Path string }
if err := json.Unmarshal([]byte(d.DisplayInfo), &displayInfo); err != nil {
log.Fatal(err)
}
fmt.Println(d.ID, displayInfo.Path)
}
playground