Use of Go language JSON standard library

Keywords: Go JSON

In Go language encoding/json The library provides complex functions to convert various types in Go to JSON format. We mainly use the following functions:

  • Serialize a slice, structure or dictionary into a JSON format string [byte stream].
  • Deserialize a JSON format string [byte stream] into a slice, structure or dictionary.

serialize

Serialization uses the Marshal function in the json Library:

func Marshal(v interface{}) ([]byte, error)

1. Structure serialization

For example, use the following structure to represent a movie:

	type Movie struct {
		Title  string
		Year   int  `json:"released"`
		Color  bool `json:"color,omitempty"`
		Actors []string
	}

The strings json:"released" and json: "color, integrity" followed by the type in the definition are called field tags, which tell the json library some rules during serialization:

  • json:"released" makes the corresponding name after serialization "released" instead of "Year".
  • JSON: "Color, omitty" makes it ignored and not serialized if the value of the Color member is false.

Some rules for serialization without field tags:

  • If the name of a structure member does not start with an uppercase letter, it is not serialized.
  • If the name of a structure member starts with an uppercase letter, the serialized name is the member name.

The code for serialization is as follows:

	movie := Movie{
		Title:  "Casablanca",
		Year:   1942,
		Color:  false,
		Actors: []string{"Humphrey Bogart", "Ingrid Bergman"},
	}
	
	data, err := json.Marshal(movie)
	if err != nil {
		log.Fatalf("JSON marshaling failed: %s", err)
	}
	fmt.Printf("%s\n", data)

Output:

{"Title":"Casablanca","released":1942,"Actors":["Humphrey Bogart","Ingrid Bergman"]}

2. Dictionary serialization

To serialize a dictionary into JSON format, its key must be a string.
Here is an example:

	info := map[string]int{
		"width":  1280,
		"height": 720,
	}
	
	data, err := json.MarshalIndent(info, "", " ")
	if err != nil {
		log.Fatalf("JSON marshaling failed: %s", err)
	}
	fmt.Printf("%s\n", data)

Output:

{
 "height": 720,
 "width": 1280
}

Here, we use the MarshalIndent function to make the output JSON format easier to read. The serialized name is the name of the key in the dictionary.

3. Slice serialization

Look directly at an example:

	type Movie struct {
		Title  string
		Year   int  `json:"released"`
		Color  bool `json:"color,omitempty"`
		Actors []string
	}

	var movies = []Movie{
		{
			Title:  "Casablanca",
			Year:   1942,
			Color:  false,
			Actors: []string{"Humphrey Bogart", "Ingrid Bergman"},
		},
		{
			Title:  "Cool Hand Luke",
			Year:   1967,
			Color:  true,
			Actors: []string{"Paul Newman"},
		},
		{
			Title:  "Bullitt",
			Year:   1968,
			Color:  true,
			Actors: []string{"Steve McQueen", "Jacqueline Bisset"},
		},
	}
	data, err := json.MarshalIndent(movies, "", " ")
	if err != nil {
		log.Fatalf("JSON marshaling failed: %s", err)
	}
	fmt.Printf("%s\n", data)

Output:

[
 {
  "Title": "Casablanca",
  "released": 1942,
  "Actors": [
   "Humphrey Bogart",
   "Ingrid Bergman"
  ]
 },
 {
  "Title": "Cool Hand Luke",
  "released": 1967,
  "color": true,
  "Actors": [
   "Paul Newman"
  ]
 },
 {
  "Title": "Bullitt",
  "released": 1968,
  "color": true,
  "Actors": [
   "Steve McQueen",
   "Jacqueline Bisset"
  ]
 }
]

Deserialization

Deserialization uses the Unmarshal function:

func Unmarshal(data []byte, v interface{}) error

1. Clearly know JSON format

We will first express the JSON format as a definite type.

1. The following JSON format:

	{
		"name": "Awesome 4K",
		"resolutions": [
			{
				"width": 1280,
				"height": 720
			},
			{
				"width": 1920,
				"height": 1080
			},
			{
				"width": 3840,
				"height": 2160
			}
		]
	}

To deserialize it into a Go object, we can represent it with the following structure:

struct {
	Name        string
	Resolutions []struct {
		Width  int
		Height int
	}
}

2. The following JSON format represents resolution information:

{
 "height": 720,
 "width": 1280
}

You can also use map[string]int, that is, dictionary to represent:

3. The following JSON format:

 [
	{
		"width": 1280,
		"height": 720
	},
	{
		"width": 1920,
		"height": 1080
	},
	{
		"width": 3840,
		"height": 2160
	}
]

Represented by slice [] map[string]int.

In any case, a certain JSON format can always be represented by a tangent, structure, or dictionary.

Then you can deserialize:

	var jsonBlob = []byte(`
	[
		{
			"width": 1280,
			"height": 720
		},
		{
			"width": 1920,
			"height": 1080,
		},
		{
			"width": 3840,
			"height": 2160
		}
	]
	`)

	di := []map[string]int{}
	err = json.Unmarshal(jsonBlob, &di)
	if err != nil {
		fmt.Println("error:", err)
	}
	fmt.Printf("%+v\n", di)

output

[map[height:720 width:1280] map[height:1080 width:1920] map[height:2160 width:3840]]

2. Unable to determine JSON format

The format that cannot be determined can be directly represented by the interface {} type. At this time, if it is a json object, the json library will use the map[string]interface {} type to represent it during deserialization. If it is a json array, it will use the [] interface {} type to represent it. Type assertion is required for the specific type corresponding to the specific interface {}.

See an example:

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	var jsonBlob = []byte(`
		{
			"name": "Awesome 4K",
			"price": 1999.9,
			"resolutions": [
				{
					"width": 1280,
					"height": 720
				},
				{
					"width": 1920,
					"height": 1080
				},
				{
					"width": 3840,
					"height": 2160
				}
			]
		}
	`)

	var d interface{}
	err := json.Unmarshal(jsonBlob, &d)
	if err != nil {
		fmt.Println("error:", err)
	}

	fmt.Println(d)

	m := d.(map[string]interface{})
	for k, v := range m {
		switch vv := v.(type) {
		case string:
			fmt.Println(k, "is string", vv)
		case float64:
			fmt.Println(k, "is float64", vv)
		case []interface{}:
			fmt.Println(k, "is an array:")
			for i, u := range vv {
				fmt.Println(i, u)
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}
}

Posted by vtolbert on Thu, 21 Oct 2021 13:04:14 -0700