In today's post, we will walk through several scenarios to parse json
files in Golang. JSON (JavaScript Object Notation) is a simple data interchange format. Syntactically it resembles the objects and lists of JavaScript. It is most commonly used for communication between web back-ends and JavaScript programs running in the browser, but it is used in many other places, too. Its home page, json.org, provides a wonderfully clear and concise definition of the standard.
With thejson package it’s a snap to read and write JSON data from your Go programs using Unmarshal()
.
Package json implements encoding and decoding of JSON as defined inRFC 7159. The mapping between JSON and Go values is described in the documentation for the Marshal and Unmarshal functions.
Golang JSON Unmarshal() Examples
Example-1: Parse structured JSON data
func Unmarshal(data []byte, v any) error
: Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError
.
Here's an example of parsing a json
file to a struct.
json
file:
{ "name": "Harry Potter", "score": 9.5 }
Code:
package mainimport ("encoding/json""fmt""io/ioutil""os")type Student struct {Name string `json:"name"`Score float64 `json:"score"`}func main() {// open json filejsonFile, err := os.Open("student.json")// if return error, print out itif err != nil {fmt.Println(err)}fmt.Println("Successfully open student.json")// defer the closing of json filedefer jsonFile.Close() // Unmarshal() function accepts []byte as parambyteValue, _ := ioutil.ReadAll(jsonFile)var student Studenterr = json.Unmarshal(byteValue, &student)if err != nil {panic(err)}fmt.Printf("%+v\n", student)}
Output:
Successfully open student.json{Name:Harry Potter Score:9.5}
Example-2: Parsing Structured Complex JSON data
For example, we want to parse this json
file:
{ "id": "0001", "type": "donut", "name": "Cake", "ppu": 0.55, "batters": { "batter": [ { "id": "1001", "type": "Regular" }, { "id": "1002", "type": "Chocolate" }, { "id": "1003", "type": "Blueberry" }, { "id": "1004", "type": "Devil's Food" } ] }, "topping": [ { "id": "5001", "type": "None" }, { "id": "5002", "type": "Glazed" }, { "id": "5005", "type": "Sugar" }, { "id": "5007", "type": "Powdered Sugar" }, { "id": "5006", "type": "Chocolate with Sprinkles" }, { "id": "5003", "type": "Chocolate" }, { "id": "5004", "type": "Maple" } ] }
We can see that we have to parse json
file to a struct which contains nested struct.
package mainimport ("encoding/json""fmt""io/ioutil""os")type Cake struct {ID string `json:"id"`Type string `json:"type"`Name string `json:"name"`Ppu float64 `json:"ppu"`Batters struct {Batter []Batter} `json:"batters"`Topping []struct {ID string `json:"id"`Type string `json:"type"`} `json:"topping"`}type Batter struct {ID stringType string}func main() {// open json filejsonFile, err := os.Open("complex.json")// if os.Open returns an error then print out itif err != nil {fmt.Println(err)}fmt.Println("Successfully Opened complex.json")// defer the closing of the json filedefer jsonFile.Close()byteValue, _ := ioutil.ReadAll(jsonFile)var cake Cakeerr = json.Unmarshal(byteValue, &cake)if err != nil {panic(err)}fmt.Printf("Type: %+v\n", cake.Type)fmt.Printf("Name: %+v\n", cake.Name)fmt.Printf("Batters: %+v\n", cake.Batters)}
Output:
Successfully Opened complex.jsonType: donutName: CakeBatters: {Batter:[{ID:1001 Type:Regular} {ID:1002 Type:Chocolate} {ID:1003 Type:Blueberry} {ID:1004 Type:Devil's Food}]}
Noted that:
- Struct's fields need to be exported (upper-case).
- Go uses convention to determine the attribute name for mapping JSON properties. If you want a different attribute name than the one provided in JSON data, you can specify mapping to field by specify json tag. To have the JSON parser/writer skip a field, just give it the name
"-"
. The JSON parser accepts a flag in the tag to indicate what to do if the field is empty. Theomitempty
flag instructs it not to include the JSON value in the output if it is the type's "zero-value." The "zero-value" for numbers is 0, the empty string for strings, and nil for maps, slices, and pointers. This is how theomitempty
flag is included. For example:
type Student struct { Name string `json:"fullName,omitempty"` Score float64 `json:"-"`}
We can defined a nested struct instead of 2 structs like the above example:
type Cake struct {ID string `json:"id"`Type string `json:"type"`Name string `json:"name"`Ppu float64 `json:"ppu"`Batters struct {Batter []struct {ID string `json:"id"`Type string `json:"type"`} `json:"batter"`} `json:"batters"`Topping []struct {ID string `json:"id"`Type string `json:"type"`} `json:"topping"`}
Example-3: Parsing Unstructured Data
In some cases, we do not know the structure of your JSON properties beforehand, so we cannot define structs to unmarshal
your data. To deal with these cases we have to create a map of strings to empty interfaces. Let's take a look at the below example:
json
file:
{"id":123,"name":"GoLinux Cloud","address":{"street":"Summer","city":"San Jose",},"phoneNumber": 1234567890,"role":"Admin", "someField": "unstructed"}
Code:
package mainimport ("encoding/json""fmt""io/ioutil""os")func main() {// open json filejsonFile, err := os.Open("unstructed.json")// if return error, print out itif err != nil {fmt.Println(err)}fmt.Println("Successfully open unstructed.json")// defer the closing of json filedefer jsonFile.Close()byteValue, _ := ioutil.ReadAll(jsonFile)var dev map[string]interface{}err = json.Unmarshal(byteValue, &dev)if err != nil {panic(err)}//iterate through the mapfor key, value := range dev {fmt.Println(key, value)}}
Output:
Successfully open unstructed.jsonid 123name GoLinux Cloudaddress map[city:San Jose street:Summer]phoneNumber 1.23456789e+09role AdminsomeField unstructed
Summary
In this tutorial, we have show you some example of using Unmarshal()
function to parse both struct and unstructured data. Go is a strongly typed language, and therefore working with JSON is always going to be tricky. Check the err
parameter returned by Marshal
and Unmarshal
at all times. It's how you know if there is a syntax error in the JSON you're parsing. If you don't check it, your program will continue to run with the zeroed-out struct you've already created, potentially leading to unexpected behavior.
References
https://pkg.go.dev/encoding/json#Marshal
https://pkg.go.dev/encoding/json
Can't find what you're searching for? Let us assist you.
Enter your query below, and we'll provide instant results tailored to your needs.