I am trying to read the following JSON file:
{
"a":1,
"b":2,
"c":3
}
I have tried this but I found that I had to write each field of the JSON file into a struct but I really don't want to have all my JSON file in my Go code.
import (
"fmt"
"encoding/json"
"io/ioutil"
)
type Data struct {
A string `json:"a"`
B string `json:"b"`
C string `json:"c"`
}
func main() {
file, _ := ioutil.ReadFile("/path/to/file.json")
data := Data{}
if err := json.Unmarshal(file ,&data); err != nil {
panic(err)
}
for _, letter := range data.Letter {
fmt.Println(letter)
}
}
Is there a way to bypass this thing with something like json.load(file) in Python?
If you only want to support integer values, you could unmarshal your data into a map[string]int. Note that the order of a map is not defined, so the below program's output is non-deterministic for the input.
package main
import (
"fmt"
"encoding/json"
"io/ioutil"
)
func main() {
file, _ := ioutil.ReadFile("/path/to/file.json")
var data map[string]int
if err := json.Unmarshal(file ,&data); err != nil {
panic(err)
}
for letter := range data {
fmt.Println(letter)
}
}
You can unmarshal any JSON data in this way:
var data interface{}
if err := json.Unmarshal(..., &data); err != nil {
// handle error
}
Though, in this way you should handle all the reflection-related stuffs
since you don't know what type the root data is, and its fields.
Even worse, your data might not be map at all.
It can be any valid JSON data type like array, string, integer, etc.
Here's a playground link: https://play.golang.org/p/DiceOv4sATO
It's impossible to do anything as simple as in Python, because Go is strictly typed, so it's necessary to pass your target into the unmarshal function.
What you've written could otherwise be shortened, slightly, to something like this:
func UnmarshalJSONFile(path string, i interface{}) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
return json.NewDecoder(f).Decode(i)
}
But then to use it, you would do this:
func main() {
data := Data{}
if err := UnmarshalJSONFile("/path/to/file.json", &data); err != nil {
panic(err)
}
}
But you can see that the UnmarshalJSONFile is so simple, it hardly warrants a standard library function.
Related
I have a hard time understanding why the code below, which uses the unmarshal method does not work, but then almost the same I write with NewDecoder and it works fine.
package conf
import (
"os"
"io/ioutil"
"encoding/json"
)
type Configuration struct {
Agents []Agent `json:"agents"`
IbmWmqFolder string `json:"ibmWmqFolder"`
}
type Agent struct {
AgentName string `json:"agentName"`
Folders []string `json:"folders"`
}
func LoadConfiguration() (configuration Configuration) {
jsonFile, err := os.Open("config.json")
if err != nil {
panic(err)
}
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
json.Unmarshal(byteValue, configuration)
return
}
but if I do all the same but instead of the two last lines with the byteValue and the unmarshal itself, but use the decoder, it works,
jsonParser := json.NewDecoder(jsonFile)
jsonParser.Decode(&configuration)
return
Thanks!
I would guess that you need to pass a pointer to the configuration, like so:
json.Unmarshal(byteValue, &configuration)
You should also check the error value returned by Unmarshal, e.g.:
err = json.Unmarshal(byteValue, &configuration)
if err != nil {
panic(err)
}
See the the docs.
I am fairly new to Go. I have the following code:
package main
import (
"encoding/json"
"fmt"
)
func main() {
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
dat := []byte(`{"num":7.13,"strs":["c","d"]}`)
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
}
Getting the error:
cannot "unmarshal object into Go value of type []uint8".
How can I fix this please?
You have 2 JSON inputs, and you're trying to unmarshal one into the other. That doesn't make any sense.
Model your JSON input (the object) with a type (struct), and unmarshal into that. For example:
type Obj struct {
Num float64 `json:"num"`
Strs []string `json:"strs"`
}
func main() {
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
panic(err)
}
fmt.Println(obj)
}
Output (try it on the Go Playground):
{6.13 [a b]}
I think you meant to do something like this:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var dat interface{}
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
}
What you were trying to do makes no sense, since you're trying to unmarshal two JSON objects one into another.
I am writing a function that parses a config JSON file and using json.Unmarshal stores its data in a struct. I've done some research and it's gotten me the point where I have a Config struct and a Server_Config struct as a field in config to allow me to add more fields as I want different config-like structs.
How can I write one parseJSON function to work for different types of structs?
Code:
Server.go
type Server_Config struct {
html_templates string
}
type Config struct {
Server_Config
}
func main() {
config := Config{}
ParseJSON("server_config.json", &config)
fmt.Printf("%T\n", config.html_templates)
fmt.Printf(config.html_templates)
}
config.go
package main
import(
"encoding/json"
"io/ioutil"
"log"
)
func ParseJSON(file string, config Config) {
configFile, err := ioutil.ReadFile(file)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(configFile, &config)
if err != nil {
log.Fatal(err)
}
}
Or if there is a better way to do all this let me know that as well. Pretty new to Go and I have Java conventions carved into my brain.
Use interface{}:
func ParseJSON(file string, val interface{}) {
configFile, err := ioutil.ReadFile(file)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(configFile, val)
if err != nil {
log.Fatal(err)
}
}
Calling the function is the same.
For example:
{"id":
{"12345678901234":
{"Account":"asdf",
"Password":"qwerty"
"LastSeen":"1397621470",
}
}
}
A program I've been trying to make needs to get the id as a string and then later use it to check the time in LastSeen.
I've tried using simplejson and jsonq,but still cant figure out how to do that.
You can use RawMessage and make it much simpiler (play with it) :
package main
import (
"encoding/json"
"fmt"
)
var data []byte = []byte(`{"id": {"12345678901234": {"Account":"asdf", "Password":"qwerty", "LastSeen":"1397621470"}}}`)
type Message struct {
Id string
Info struct {
Account string
Password string
LastSeen string
}
}
func main() {
var (
tmpmsg struct {
Data map[string]json.RawMessage `json:"id"`
}
msg Message
)
if err := json.Unmarshal(data, &tmpmsg); err != nil {
panic(err) //you probably wanna use or something instead
}
for id, raw := range tmpmsg.Data {
msg.Id = id
if err := json.Unmarshal(raw, &msg.Info); err != nil {
panic(err)
}
}
fmt.Printf("%+v\n", msg)
}
Looking at the Golang blog post on JSON here it can be done using the encoding/json package. I created a small program to do this as follows:
package main
import (
"encoding/json"
"fmt"
)
var data []byte = []byte(`{"id": {"12345678901234": {"Account":"asdf", "Password":"qwerty", "LastSeen":"1397621470"}}}`)
type Message struct {
id string
LastSeen int64
}
var m Message
func main() {
var i interface {}
err := json.Unmarshal(data, &i)
if err != nil {
println("Error decoding data")
fmt.Printf("%s", err.Error())
return
}
m := i.(map[string]interface{})
for k, v := range m {
println(k)
im := v.(map[string]interface{})
for ik, iv := range im {
println("\t", ik)
jm := iv.(map[string]interface{})
for jk, jv := range jm {
println("\t\t", jk, ": ", jv.(string))
}
}
}
}
I apologise if this is poor in terms of Go best practices and such, I am new to the language. And I know that some elements of this aren't entirely necessary like the Message type definition but this works, at least on your data.
In Go, I have some JSON from third-party API and then I'm trying to parse it:
b := []byte(`{"age":21,"married":true}`)
var response_hash map[string]string
_ = json.Unmarshal(b, &response_hash)
But it fails (response_hash becomes empty) and Unmarshal can handle only JSON with quotes:
b := []byte(`{"age":"21","married":"true"}`)
var response_hash map[string]string
_ = json.Unmarshal(b, &response_hash)
Is there any way to read the first version of JSON from third-party API?
Go is a strongly typed language. You need to specify what types the JSON encoder is to expect. You're creating a map of string values but your two json values are an integer and a boolean value.
Here's a working example with a struct.
http://play.golang.org/p/oI1JD1UUhu
package main
import (
"fmt"
"encoding/json"
)
type user struct {
Age int
Married bool
}
func main() {
src_json := []byte(`{"age":21,"married":true}`)
u := user{}
err := json.Unmarshal(src_json, &u)
if err != nil {
panic(err)
}
fmt.Printf("Age: %d\n", u.Age)
fmt.Printf("Married: %v\n", u.Married)
}
If you want to do it in a more dynamic manner you can use a map of interface{} values. You just have to do type assertions when you use the values.
http://play.golang.org/p/zmT3sPimZC
package main
import (
"fmt"
"encoding/json"
)
func main() {
src_json := []byte(`{"age":21,"married":true}`)
// Map of interfaces can receive any value types
u := map[string]interface{}{}
err := json.Unmarshal(src_json, &u)
if err != nil {
panic(err)
}
// Type assert values
// Unmarshal stores "age" as a float even though it's an int.
fmt.Printf("Age: %1.0f\n", u["age"].(float64))
fmt.Printf("Married: %v\n", u["married"].(bool))
}