unmarshal json file with multiple json object (not valid json file) [duplicate] - json

This question already has answers here:
Parsing multiple JSON objects in Go
(4 answers)
Closed 2 years ago.
I have a json file (file.json) with following content:
file.json:
{"job": "developer"}
{"job": "taxi driver"}
{"job": "police"}
The contents of the file are exactly as above (not valid json file)
I want use data in my code but I can not Unmarshal This

What you have is not a single JSON object but a series of (unrelated) JSON objects. You can't use json.Unmarshal() to unmarshal something that contains multiple (independent) JSON values.
Use json.Decoder to decode multiple JSON values (objects) from a source one-by-one.
For example:
func main() {
f := strings.NewReader(file)
dec := json.NewDecoder(f)
for {
var job struct {
Job string `json:"job"`
}
if err := dec.Decode(&job); err != nil {
if err == io.EOF {
break
}
panic(err)
}
fmt.Printf("Decoded: %+v\n", job)
}
}
const file = `{"job": "developer"}
{"job": "taxi driver"}
{"job": "police"}`
Which outputs (try it on the Go Playground):
Decoded: {Job:developer}
Decoded: {Job:taxi driver}
Decoded: {Job:police}
This solution works even if your JSON objects take up multiple lines in the source file, or if there are multiple JSON objects in the same line.
See related: I was getting output of exec.Command output in the following manner. from that output I want to get data which I needed

You can read string line by line and unmarshal it:
package main
import (
"bufio"
"encoding/json"
"fmt"
"strings"
)
type j struct {
Job string `json:"job"`
}
func main() {
payload := strings.NewReader(`{"job": "developer"}
{"job": "taxi driver"}
{"job": "police"}`)
fscanner := bufio.NewScanner(payload)
for fscanner.Scan() {
var job j
err := json.Unmarshal(fscanner.Bytes(), &job)
if err != nil {
fmt.Printf("%s", err)
continue
}
fmt.Printf("JOB %+v\n", job)
}
}
Output:
JOB {Job:developer}
JOB {Job:taxi driver}
JOB {Job:police}
Example

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.

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.

Is there a way to extract JSON from an http response without having to build structs?

All of the ways I'm seeing involve building structs and unmarshalling the data into the struct. But what if I'm getting JSON responses with hundreds of fields? I don't want to have to create 100 field structs just to be able to get to the data I want. Coming from a Java background there are easy ways to simply get the http response as a string and then pass the JSON string into a JSON object that allows for easy traversal. It's very painless. Is there anything like this in Go?
Java example in pseudo code:
String json = httpResponse.getBody();
JsonObject object = new JsonObject(json);
object.get("desiredKey");
Golang: fetch JSON from an HTTP response without using structs as helpers
This is a typical scenario we come across. This is achieved by json.Unmarshal.
Here is a simple json
{"textfield":"I'm a text.","num":1234,"list":[1,2,3]}
which is serialized to send across the network and unmarshaled at Golang end.
package main
import (
"fmt"
"encoding/json"
)
func main() {
// replace this by fetching actual response body
responseBody := `{"textfield":"I'm a text.","num":1234,"list":[1,2,3]}`
var data map[string]interface{}
err := json.Unmarshal([]byte(responseBody), &data)
if err != nil {
panic(err)
}
fmt.Println(data["list"])
fmt.Println(data["textfield"])
}
Hope this was helpful.
The json.Unmarshal method will unmarshal to a struct that does not contain all the fields in the original JSON object. In other words, you can cherry-pick your fields. Here is an example where FirstName and LastName are cherry-picked and MiddleName is ignored from the json string:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
func main() {
jsonString := []byte("{\"first_name\": \"John\", \"last_name\": \"Doe\", \"middle_name\": \"Anderson\"}")
var person Person
if err := json.Unmarshal(jsonString, &person); err != nil {
panic(err)
}
fmt.Println(person)
}
The other answers here are misleading, as they don't show you what happens if you try to go deeper in the Map. This example works fine enough:
package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
r, e := http.Get("https://github.com/manifest.json")
if e != nil {
panic(e)
}
body := map[string]interface{}{}
json.NewDecoder(r.Body).Decode(&body)
/*
[map[
id:com.github.android
platform:play
url:https://play.google.com/store/apps/details?id=com.github.android
]]
*/
fmt.Println(body["related_applications"])
}
but if you try to go one level deeper, it fails:
/*
invalid operation: body["related_applications"][0] (type interface {} does not
support indexing)
*/
fmt.Println(body["related_applications"][0])
Instead, you would need to assert type at each level of depth:
/*
map[
id:com.github.android
platform:play
url:https://play.google.com/store/apps/details?id=com.github.android
]
*/
fmt.Println(body["related_applications"].([]interface{})[0])
You can as well unmarshal it into a map[string]interface{}
body, err := ioutil.ReadAll(resp.Body)
map := &map[string]interface{}{}
json.Unmarshal(body, map)
desiredValue := map["desiredKey"]
The received json must have an object as the most outer element. The map can also contain lists or nested maps, depending on the json.

How do I read one value from a JSON file using Go

I an new to programming in Go so apologies if this is something obvious. I have a JSON file named foo.json:
{"type":"fruit","name":"apple","color":"red"}
and I am writing a Go program that has to do something when the "name" value in the JSON file is "apple". It needs no other information from that JSON file as that file is used for a completely different purpose in another area of the code.
I have read documentation on Decode() and Unmarshal() and abut 30 different web pages describing how to read the whole file into structures, etc. but it all seems extremely complicated for what I want to do which is just write the correct code to implement the first 2 lines of this pseudo-code:
file, _ := os.Open("foo.json")
name = file["name"]
if (name == "apple") {
do stuff
}
such that I end up with a Go variable named name that contains the string value apple. What is the right way to do this in Go?
The easiest method to do what you want is to decode into a struct.
Provided the format remains similar to {"type":"fruit","name":"apple","color":"red"}
type Name struct {
Name string `json:"name"`
}
var data []byte
data, _ = ioutil.ReadFile("foo.json")
var str Name
_ = json.Unmarshal(data, &str)
if str.Name == "apple" {
// Do Stuff
}
Your other option is to use third party libraries such as gabs or jason.
Gabs :
jsonParsed, err := gabs.ParseJSON(data)
name, ok := jsonParsed.Path("name").Data().(string)
Jason :
v, _ := jason.NewObjectFromBytes(data)
name, _ := v.GetString("name")
Update :
The structure
type Name struct {
Name string `json:"name"`
}
is the json equivalent of {"name":"foo"}.
So unmarshaling won't work for the following json with different formats.
[{"name":"foo"}]
{"bar":{"name":"foo"}}
PS : As mentioned by W.K.S. In your case an anonymous struct would suffice since you're not using this structure for anything else.
One thing is reading a file and other one is decoding a JSON document. I leave you a full example doing both. To run it you have to have a file called file.json in the same directory of your code or binary executable:
package main
import (
"encoding/json"
"io/ioutil"
"log"
"os"
)
func main() {
f, err := os.Open("file.json") // file.json has the json content
if err != nil {
log.Fatal(err)
}
bb, err := ioutil.ReadAll(f)
if err != nil {
log.Fatal(err)
}
doc := make(map[string]interface{})
if err := json.Unmarshal(bb, &doc); err != nil {
log.Fatal(err)
}
if name, contains := doc["name"]; contains {
log.Printf("Happy end we have a name: %q\n", name)
} else {
log.Println("Json document doesn't have a name field.")
}
log.Printf("full json: %s", string(bb))
}
https://play.golang.org/p/0u04MwwGfn
I have also tried to find a simple solution such as $d = json_decode($json, true) in PHP and came to the conclusion that there is no such simple way in Golang. The following is the simplest solution I could make (the checks are skipped for clarity):
var f interface{}
err = json.Unmarshal(file, &f)
m := f.(map[string]interface{})
if (m["name"] == "apple") {
// Do something
}
where
file is an array of bytes of JSON string,
f interface serves as a generic container for unknown JSON structure,
m is a map returned by the type assertion.
We can assert that f is a map of strings, because Unmarshal() builds a variable of that type for any JSON input. At least, I couldn't make it return something different. It is possible to detect the type of a variable by means of run-time reflection:
fmt.Printf("Type of f = %s\n", reflect.TypeOf(f))
For the f variable above, the code will print Type of f = map[string]interface {}.
Example
And this is the full code with necessary checks:
package main
import (
"fmt"
"os"
"io/ioutil"
"encoding/json"
)
func main() {
// Read entire file into an array of bytes
file, err := ioutil.ReadFile("foo.json")
if (err != nil) {
fmt.Fprintf(os.Stderr, "Failed read file: %s\n", err)
os.Exit(1)
}
var f interface{}
err = json.Unmarshal(file, &f)
if (err != nil) {
fmt.Fprintf(os.Stderr, "Failed to parse JSON: %s\n", err)
os.Exit(1)
}
// Type-cast `f` to a map by means of type assertion.
m := f.(map[string]interface{})
fmt.Printf("Parsed data: %v\n", m)
// Now we can check if the parsed data contains 'name' key
if (m["name"] == "apple") {
fmt.Print("Apple found\n")
}
}
Output
Parsed data: map[type:fruit name:apple color:red]
Apple found
The proper Go way of doing this would be to decode into an instance of an anonymous struct containing only the field you need.
func main() {
myStruct := struct{ Name string }{}
json.Unmarshal([]byte(`{"type":"fruit","name":"apple","color":"red"}`), &myStruct)
fmt.Print(myStruct.Name)
}
Playground Link
Alternatively, You could use Jeffails/gabs JSON Parser:
jsonParsed,_ := gabs.ParseJSON([]byte(`{"type":"fruit","name":"apple","color":"red"}`));
value, ok = jsonParsed.Path("name").Data().(string)

Golang parse JSON array into data structure

I am trying to parse a file which contains JSON data:
[
{"a" : "1"},
{"b" : "2"},
{"c" : "3"}
]
Since this is a JSON array with dynamic keys, I thought I could use:
type data map[string]string
However, I cannot parse the file using a map:
c, _ := ioutil.ReadFile("c")
dec := json.NewDecoder(bytes.NewReader(c))
var d data
dec.Decode(&d)
json: cannot unmarshal array into Go value of type main.data
What would be the most simple way to parse a file containing a JSON data is an array (only string to string types) into a Go struct?
EDIT: To further elaborate on the accepted answer -- it's true that my JSON is an array of maps. To make my code work, the file should contain:
{
"a":"1",
"b":"2",
"c":"3"
}
Then it can be read into a map[string]string
Try this: http://play.golang.org/p/8nkpAbRzAD
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
)
type mytype []map[string]string
func main() {
var data mytype
file, err := ioutil.ReadFile("test.json")
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(file, &data)
if err != nil {
log.Fatal(err)
}
fmt.Println(data)
}
It's because your json is actually an array of maps, but you're trying to unmarshall into just a map. Try using the following:
type YourJson struct {
YourSample []struct {
data map[string]string
}
}
you can try the bitly's simplejson package
https://github.com/bitly/go-simplejson
it's much easier.