Unmarshal JSON with unknown field name [duplicate] - json

This question already has answers here:
How to parse/deserialize dynamic JSON
(4 answers)
Closed 3 years ago.
I have a JSON object, something like this:
{
"randomstring": {
"everything": "here",
"is": "known"
}
}
Basically everything inside the randomstring object is known, I can model that, but the randomstring itself is random. I know what it's going to be, but it's different every time. Basically all the data I need is in the randomstring object. How could I parse this kind of JSON to get the data?

Use a map where the key type is string and the value type is a struct with the fields you want, like in this example on the Playground and below:
package main
import (
"encoding/json"
"fmt"
"log"
)
type Item struct{ X int }
var x = []byte(`{
"zbqnx": {"x": 3}
}`)
func main() {
m := map[string]Item{}
err := json.Unmarshal(x, &m)
if err != nil {
log.Fatal(err)
}
fmt.Println(m)
}

Related

How to deserialize a json with an array of anonymous arrays in Golang? [duplicate]

This question already has an answer here:
Go json array of arrays
(1 answer)
Closed 9 days ago.
I am receiving this json from an external server:
[["010117", "070117", "080117"], ["080117", "140117", "150117"], ["150117", "210117", "220117"]]
and i need to parse it
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"runtime"
)
type Range struct {
From string
To string
Do string
}
type AllRanges struct {
Ranges []Range
}
func main() {
var ranges AllRanges
j, err := os.ReadFile(file)
if err != nil {
panic("Can't read json file")
}
if json.Unmarshal(j, &v) != nil {
panic("Error reading the json")
}
}
When I execute, a panic it is thrown indicating an error reading the json
Thanks in advance !
This isn't the code that is failing. The code you have posted won't compile as it attempts to unmarshal into an undeclared variable, v.
Assuming that v is supposed to be ranges, the problem is very simple....
ranges is of type AllRanges which is a struct having a named member Ranges which is an array of structs, also having named members.
Therefore, when attempting to unmarshal json into this struct, the unmarshaller will expect to find:
{
"Ranges": [
{
"From": "..",
"To": ..,
"Do": ".."
},
{ etc }
]
}
To unmarshal your data, consisting of an anonymous array of arrays of string, you need instead to declare ranges as an array of array of strings:
var ranges [][]string
...
if json.Unmarshal(j, &ranges) != nil {
panic("Error reading the json")
}
Once you have unmarshalled into this array of arrays you will then need to write code to transform it into the desired structured values.
This playground demonstrates successfully unmarshalling your sample data into a [][]string. Transformation is left as an exercise.

Cannot unmarshal array of lists where elements don't have the same type [duplicate]

This question already has answers here:
Custom unmarshaling a struct into a map of slices
(1 answer)
How to parse a complicated JSON with Go unmarshal?
(3 answers)
golang | unmarshalling arbitrary data
(2 answers)
How to parse JSON in golang without unmarshaling twice
(3 answers)
Decoding generic JSON objects to one of many formats
(1 answer)
Closed 9 months ago.
I'm scraping Binance API for candle price data. The Binance API provides the said data as json array. Each element of the array is a list representing candle and does not contain elements of the same type, however each list contains the same set of types: strings and ints, to be precise. Look at the raw data of this for instance: https://api.binance.com/api/v3/klines?symbol=ZECUSDT&interval=1h&limit=10&startTime=1653001200000
How do I automatically unmarshal such json into struct? Is using reflect the only option here?
package main
import (
"encoding/json"
"log"
"net/http"
"os"
"os/signal"
"syscall"
)
type PriceData struct {
Data map[int]Price
}
type Price struct {
TradeStart uint64 `json:"0"` // tried without json tags
PriceOpen string `json:"1"`
PriceHigh string `json:"2"`
PriceLow string `json:"3"`
PriceClose string `json:"4"`
TradeEnd uint64 `json:"6"`
// QuoteVolume string // tried with these fields as well
// NumberOfTrades uint64
// TakerBuyBaseVolume string
// TakerBuyQuoteVolume string
}
func main() {
url := "https://api.binance.com/api/v3/klines?symbol=ZECUSDT&interval=1h&limit=10&startTime=1653001200000" // tried /api/v1 as well
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
// var priceData map[int]Price // -- tried
// var priceData []Price // -- tried
// var priceData PriceData // -- tried
// var priceData []interface{} -- works fine, but will need to use reflection
var priceData []Price
if err = json.Unmarshal(content, &priceData); err != nil {
log.Fatal(err)
}
interupt := make(chan os.Signal, 1)
signal.Notify(interupt, syscall.SIGTERM, syscall.SIGINT)
<-interupt
}

using maps with any value type as function parameter? [duplicate]

This question already has answers here:
generic map value
(2 answers)
Closed 8 months ago.
I am trying to create a function which takes in a map as a parameter, where the map uses string keys but the values can be ANY type.
How do I make this work in go? I tried using map[string]interface{} as the parameter type to the function but that does not seem to work for example when passing in a map[string]int as an argument.
Any explanations as to what is the problem with this approach and if there is a way to achieve this in go?
If a function parameter is of type map[string]interface{} then you need to pass it a map[string]interface{} (and map[string]int is not map[string]interface{}).
This is a common issue and is covered in the FAQ (this focuses on slices but the same principal applies to maps).
The best approach really depends upon what you are trying to accomplish. You can do something like the following (playground):
package main
import (
"fmt"
)
func main() {
v := make(map[string]interface{})
v["blah"] = 3
test(v)
v["panic"] = "string"
test(v)
}
func test(in map[string]interface{}) {
var ok bool
converted := make(map[string]int)
for k, v := range in {
converted[k], ok = v.(int)
if !ok {
panic("Unexpected type in map")
}
}
fmt.Println(converted)
}
or accept an interface{} which allows anything to be passed in (playground):
package main
import (
"fmt"
)
func main() {
v := make(map[string]int)
v["blah"] = 3
test(v)
w := make(map[string]string)
w["next"] = "string"
test(w)
x := make(map[string]bool)
x["panic"] = true
test(x)
}
func test(in interface{}) {
switch z := in.(type) {
case map[string]int:
fmt.Printf("dealing with map[string]int: %v\n", z)
case map[string]string:
fmt.Printf("dealing with map[string]string: %v\n", z)
default:
panic(fmt.Sprintf("unsupported type: %T", z))
}
// You could also use reflection here...
}

Has Json tag but not exported [duplicate]

This question already has answers here:
JSON and dealing with unexported fields
(2 answers)
(un)marshalling json golang not working
(3 answers)
Closed 4 years ago.
Begining to study golang.
Task: Get Json and Unmarshall it.
But I get mistake:
Json tag but not exported
How to make unexported fields become exported and then implement it using methods?
Here is the code:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type Time struct {
time
}
type time struct {
id string `json:"$id"`
currentDateTime string `json:"currentDateTime,string"`
utcOffset float64 `json:"utcOffset,string"`
isDayLightSavingsTime bool `json:"isDayLightSavingsTime,string"`
dayOfTheWeek string `json:"dayOfTheWeek,string"`
timeZoneName string `json:"timeZoneName,string"`
currentFileTime float64 `json:"currentFileTime,string"`
ordinalDate string `json:"ordinalDate,string"`
serviceResponse string `json:"serviceResponse,string"`
}
func (t *Time) GetTime() (Time, error) {
result := Time{}
return result, t.Timenow(result)
}
func (t *Time) Timenow(result interface{}) error {
res, err := http.Get("http://worldclockapi.com/api/json/utc/now")
if err != nil {
fmt.Println("Cannot get Json", err)
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println("Cannot create Body", err)
}
defer res.Body.Close()
var resultJson interface{}
return json.Unmarshal(body, &resultJson)
}
func main() {
var a Time
t, err := a.GetTime()
if err != nil {
fmt.Println("Error ", err)
}
fmt.Println("Time:", t)
}
Please explain in details whats wrong with struct and how to get right response?
You're adding a JSON tag to a field that isn't exported.
Struct fields must start with upper case letter (exported) for the JSON package to see their value.
struct A struct {
// Unexported struct fields are invisible to the JSON package.
// Export a field by starting it with an uppercase letter.
unexported string
// {"Exported": ""}
Exported string
// {"custom_name": ""}
CustomName string `json:"custom_name"`
}
The underlying reason for this requirement is that the JSON package uses reflect to inspect struct fields. Since reflect doesn't allow access to unexported struct fields, the JSON package can't see their value.

how to Unmarshal json in golang [duplicate]

This question already has answers here:
json.Marshal(struct) returns "{}"
(3 answers)
Closed 6 years ago.
I have a json:
{"code":200,
"msg":"success",
"data":{"url":"https:\/\/mp.weixin.qq.com\/cgi-bin\/showqrcode?ticket=gQHQ7jwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyX3pqS0pMZlA4a1AxbEJkemhvMVoAAgQ5TGNYAwQsAQAA"}}
and i define a struct :
type Result struct {
code int
msg string `json:"msg"`
data map[string]interface{} `json:"data"`
}
for this code:
var res Result
json.Unmarshal(body, &res)
fmt.Println(res)
the output is: {0 map[]}
i want to get url in data, how to get it?
You should export fields (code, msg, data) for Result by capitalizing the first letter of fields (Code, Msg, Data) to access (set/get) them:
package main
import (
"encoding/json"
"fmt"
)
type Result struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data map[string]interface{} `json:"data"`
}
func main() {
str := `{"code":200,"msg":"success","data":{"url":"https:\/\/mp.weixin.qq.com\/cgi-bin\/showqrcode?ticket=gQHQ7jwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyX3pqS0pMZlA4a1AxbEJkemhvMVoAAgQ5TGNYAwQsAQAA"}}`
var res Result
err := json.Unmarshal([]byte(str), &res)
fmt.Println(err)
fmt.Println(res)
}
Play the code on https://play.golang.org/p/23ah8e_hCa
Related question: Golang - Capitals in struct fields