Golang Parse JSON (With or Without Struct)? [SOLVED]


GO

Author: Tuan Nguyen
Reviewer: Deepak Prasad

In this post, we'll look at how to parse a JSON string for structured and unstructured data. We also handle the situation where the json string contains a backlash. In the previous post, I demonstrated how to parse a json file in Golang using the json package and Unmarshal() function. In golang, we also use this package to convert a json string to a struct. To better understand how it works, consider the following examples.

json package: Package json implements encoding and decoding of JSON as defined in RFC 7159. The mapping between JSON and Go values is described in the documentation for the Marshal and Unmarshal functions.

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.

 

Golang parse JSON into a struct

Example-1: Parse JSON from a variable into nested struct

Here is an example of parsing a json string to a nested struct data in Golang using the Unmarshal() function:

package main

import (
	"encoding/json"
	"fmt"
)

// declaring a struct
type Squad struct {
	SquadName string `json:"squadName"`
	Formed    int    `json:"formed"`
	Leader    string `json:"leader"`
	Status    bool   `json:"active"`
	Members   []struct {
		Name           string `json:"name"`
		Age            int    `json:"age"`
		SecretIdentity string `json:"secretIdentity"`
	} `json:"members"`
}

// main function
func main() {

	// defining a struct instance
	var squad Squad

	// string json
	jsonString := `{
		"squadName": "Go Linux Cloud",
		"formed": 2022,
		"leader": "",
		"active": true,
		"members": [
		  {
			"name": "Anna",
			"age": 30,
			"secretIdentity": "Duke"
		  },
		  {
			"name": "Harry Potter",
			"age": 32,
			"secretIdentity": "Jane"
		  }]}`

	// decoding squad struct from json string
	err := json.Unmarshal([]byte(jsonString), &squad)

	if err != nil {
		// print out if error is not nil
		fmt.Println(err)
	}

	// printing details of struct
	fmt.Println("Struct is:", squad)
	fmt.Println("Squad's name is:", squad.SquadName)
	fmt.Println("Squad's leader is:", squad.Leader)
	fmt.Println("1st member is:", squad.Members[0].Name)
}

Output:

Squad's name is: Go Linux Cloud
Squad's leader is:
1st member is: Anna

 

Example-2: Parse JSON from a file into struct

In this example we will read JSON from a file and parse it into a struct. Here is my sample data.json which we will use in this example:

{
    "name": "Amit Kumar",
    "age": 34,
    "address": {
        "street": "123 Some Random Street",
        "city": "Chennai",
        "state": "TN",
        "zip": "763098"
    },
    "phoneNumbers": [
        {
            "type": "home",
            "number": "0123456789"
        },
        {
            "type": "work",
            "number": "0987654321"
        }
    ]
}

We can use the json package to parse JSON data from a file into a struct. But we need to define the struct that matches the structure of JSON. Then we can use the json.Unmarshal function to parse the JSON data from a file into an instance of that struct.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
)

type Address struct {
	Street string `json:"street"`
	City   string `json:"city"`
	State  string `json:"state"`
	Zip    string `json:"zip"`
}

type PhoneNumber struct {
	Type   string `json:"type"`
	Number string `json:"number"`
}

type Person struct {
	Name        string        `json:"name"`
	Age         int           `json:"age"`
	Address     Address       `json:"address"`
	PhoneNumber []PhoneNumber `json:"phoneNumbers"`
}

func main() {
	// Read the file
	data, err := ioutil.ReadFile("data.json")
	if err != nil {
		fmt.Println(err)
		return
	}

	// Create a struct to hold the JSON data
	var person Person

	// Unmarshal the JSON data into the struct
	err = json.Unmarshal(data, &person)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Print the data
	fmt.Println(person)
}

In this example, the struct Person is defined with fields that match the structure of the JSON data. The json struct tags are used to indicate the corresponding field names in JSON.

Then, the ioutil.ReadFile function is used to read the contents of the file "data.json" into the data variable. Then the json.Unmarshal function is used to parse the JSON data into an instance of struct Person.

Note that, if the structure of the JSON is not known and we want to handle all types of JSON, then we can use map[string]interface{} instead of struct as I have shown in next examples.

Output:

# go run main.go 
{Amit Kumar 34 {123 Some Random Street Chennai TN 763098} [{home 0123456789} {work 0987654321}]}

 

Golang parse JSON without struct into map

Example-1: Parse JSON from a variable into map

In some cases, we do not know the structure of your JSON properties beforehand, so we cannot define structs to unmarshal our 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:

package main

import (
	"encoding/json"
	"fmt"
)

// main function
func main() {

	// defining a map
	var result map[string]interface{}

	// string json
	jsonString := `{
		"results": [
		  {
			"nameChunk1": [
			  {
				"name1": "Anna",
				"name2": "Bob"
			  }
			],
			"nameChunk2": [
			  {
				"name1": "Clay",
				"name2": "Dean"
			  }
			]
		  }
		],
		"author": "Go Linux Cloud"
	  }`

	err := json.Unmarshal([]byte(jsonString), &result)

	if err != nil {
		// print out if error is not nil
		fmt.Println(err)
	}

	// printing details of map
	// iterate through the map
	for key, value := range result {
		fmt.Println(key, ":", value)
	}
}

Output:

results : [map[nameChunk1:[map[name1:Anna name2:Bob]] nameChunk2:[map[name1:Clay name2:Dean]]]]
author : Go Linux Cloud

 

Parse content of JSON file into map

In the previous example we parsed JSON from a variable, now in this example we have a JSON file data.json with following content:

{
    "name": "Amit Kumar",
    "age": 34,
    "address": {
        "street": "123 Some Random Street",
        "city": "Chennai",
        "state": "TN",
        "zip": "763098"
    },
    "phoneNumbers": [
        {
            "type": "home",
            "number": "0123456789"
        },
        {
            "type": "work",
            "number": "0987654321"
        }
    ]
}

Here is a simple golang program to load data.json file and convert it into map:

package main

import (
	"encoding/json"
	"fmt"
	"os"
)

func main() {
	// Open the file
	file, err := os.Open("data.json")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	// Create a map to hold the JSON data
	var data map[string]interface{}

	// Decode the JSON data into the map
	err = json.NewDecoder(file).Decode(&data)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Print the data
	fmt.Println(data)
}

This example uses the os.Open function to open the file "data.json" and the json.NewDecoder function to read the JSON data from the file. The json.Decode method is used to parse the JSON data into the map data.

Note that the data variable is defined as map[string]interface{}. This is because the json.Decode function returns a map with keys of type string and values of type interface{}, which can hold any JSON value.

Output:

# go run main.go 
map[address:map[city:Chennai state:TN street:123 Some Random Street zip:763098] age:34 name:Amit Kumar phoneNumbers:[map[number:0123456789 type:home] map[number:0987654321 type:work]]]

Now we used os.Open to read the file but you can also use ioutil.Read() to perform the same as shown below:

	// Read the file
	data, err := ioutil.ReadFile("data.json")
	if err != nil {
		fmt.Println(err)
		return
	}

 

Golang parse JSON string with backslash

Using strconv.Unquote() function

func Unquote(s string) (string, error): Unquote interprets s as a single-quoted, double-quoted, or backquoted Go string literal, returning the string value that s quotes. (If s is single-quoted, it would be a Go character literal; Unquote returns the corresponding one-character string.)

Here is an example of parsing this string "{\"channel\":\"buu\",\"sender\":\"anna\", \"receiver\":\"bob\", \"message\":\"hello\"}" to a string map.

package main

import (
	"encoding/json"
	"fmt"
	"strconv"
)

// main function
func main() {

	// defining a map
	var result map[string]interface{}

	// string json
	jsonString := `"{\"channel\":\"buu\",\"sender\":\"anna\", \"receiver\":\"bob\", \"message\":\"hello\"}"`
        // replace \ with empty character
	s, _ := strconv.Unquote(string(jsonString))
	err := json.Unmarshal([]byte(s), &result)

	if err != nil {
		// print out if error is not nil
		fmt.Println(err)
	}

	// printing details of map
	// iterate through the map
	for key, value := range result {
		fmt.Println(key, ":", value)
	}
}

Output when we iterate through the map:

sender : anna
receiver : bob
message : hello
channel : buu

 

Using Replace() function

func Replace(s, old, new string, n int) string: Replace returns a copy of the string s with the first n non-overlapping instances of old replaced by new

In this example, we will replace backslash with empty character and then parse it like a normal json string:

package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

// main function
func main() {

	// defining a map
	var result map[string]interface{}

	// string json
	jsonString := `"{\"channel\":\"buu\",\"sender\":\"anna\", \"receiver\":\"bob\", \"message\":\"hello\"}"`
	jsonString = strings.Replace(jsonString, "\\", "", -1)
	jsonString = jsonString[1 : len(jsonString)-1]

	err := json.Unmarshal([]byte(jsonString), &result)

	if err != nil {
		// print out if error is not nil
		fmt.Println(err)
	}

	// printing details of map
	// iterate through the map
	for key, value := range result {
		fmt.Println(key, ":", value)
	}
}

The output will be the same with example 3.

 

Summary

The above examples demonstrate how to read a json string using the golang Unmarshal() function. If your json string contains a backslash, you can use Replace() or Unquote() function.

 

References

https://www.json.org/json-en.html
https://pkg.go.dev/encoding/json
https://pkg.go.dev/strings#Replace

 

Tuan Nguyen

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on his LinkedIn profile.

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.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment