SoFunction
Updated on 2025-03-03

Methods to parse dynamic JSON format using Go language

Usually, the Golang encoding/json standard library can easily encode/parse JSON data, but the premise is to define the struct data structure. Especially when parsing JSON data with unknown structures, the original method is difficult to meet the needs. This article mainly introduces dynamic analysis of JSON format.

Go language JSON library

The JSON conversion library that comes with Go language is used to encoding/json

1.1) The method (function) that converts an object to JSON is (), and its function prototype is as follows

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

That is to say, this function receives any type of data v and converts it to a byte array type. The return value is the JSON data we want and an error code. When the conversion is successful, the error code is nil

During the process of converting objects to JSON, the following rules will be followed:

  1. After converting the Boolean to JSON, it is still a Boolean, such as true -> true
  2. Floating point and integer types are converted into regular numbers in JSON, such as 1.23 -> 1.23
  3. The string will be converted into a string with UTF-8 encoding and output to a Unicode character set. Special characters such as < will be escaped as \u003c
  4. Arrays and slices are converted to arrays in JSON, []byte class will be converted to base64 encoded strings, and slice's zero value is converted to null
  5. The structure will be converted into a JSON object, and only exportable fields that start with capital letters in the structure will be converted and output, and these exportable fields will be used as string indexes for the JSON object.
  6. When converting a data structure of map type, the type of the data must be map[string]T (T can be any data type supported by the encoding/json package)

1.2) The method (function) of converting JSON back to an object is (), and its function prototype is as follows

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

This function will parse the passed data as a JSON, and the parsed data is stored in the parameter v. This parameter v is also a parameter of any type (but it must be a pointer of type). The reason is that when we use this function to parse JSON, this function does not know the specific type of the passed parameter, so it needs to receive all types.

So, when parsing, what happens if the structure of JSON and the object is not in the same way? This requires the parsing function () to follow the following rules.

The () function will look for fields in the target structure in a conventional order, and a match occurs if one is found. So what is found? Regarding "found", there are the following rules: Suppose a JSON object has an index named "Foo", and to fill the value corresponding to "Foo" on the target field of the target structure, () will follow the following order to find the match.

  1. § A field containing the Foo tag
  2. §  A field called Foo
  3. § A field named Foo or Foo or insensitive to the upper and lowercase letters except the initial letter. These fields must all be exportable fields that start with capital letters in the type declaration.

Note: If a field in JSON does not exist in the Go target type, the () function will discard the field during decoding.

When the structure of JSON is unknown, the following rules will be followed:

  1. § Boolean values ​​in JSON will be converted to bool types in Go
  2. § The value will be converted to float64 type in Go
  3. § Is it still a string type after conversion
  4. § JSON arrays will be converted to []interface{} type
  5. § JSON objects will be converted to map[string]interface{} type
  6. § null value will be converted to nil

Note: In Go's standard library encoding/json package, it is allowed to use values ​​of type map[string]interface{} and []interface{} to store JSON objects or arrays of unknown structures respectively.

1. Traditional methods

For example, the User data structure is as follows:

type User struct {
 Name string `json:"name"`
 Age int  `json:"age"`
}

When defining a struct field, you can add a tag after the field to control the process of encode/decode: whether you want to decode/encode a certain field, and what is the field name in JSON. Field name initials control the visibility of the field. To output to JSON, the initials need to be capitalized.

Three types of tags:

- :Don't parse this field

omitempty: Do not parse this field when the field is empty (default). For example, false, 0, nil, array, map, slice, string with length 0

FieldName : When parsing json, use this name

For example:

// Ignore this field during parsing.  This field is parsed by default because it starts with capital lettersField int `json:"-"`
// When parsing (encode/decode), use `other_name` instead of `Field`Field int `json:"other_name"`
// Use `other_name` when parsing. If this value in struct is empty, ignore itField int `json:"other_name,omitempty"`

(1)encode

user := User{Name: "test", Age:23}
data, err := (user)
if err != nil {
 (string(data))
}

data is an array of type []byte, which contains data parsed into JSON. You can use string(data) to transform into string.

(2)decode

To convert JSON data into a Go type value (Decode), you can use .

var user User
err = (data, &user)
if err != nil {
 ("Can not decode data: %v\n", err)
}

2. Dynamic analysis

The dynamic JSON structure is unknown. If you use the previous method, you need to define the data structure in advance, which is very different from PHP/Python JSON processing. If performance is not considered, use simplejson.

(1)simplejson

js, err := ([]byte(`{
 "test": {
  "string_array": ["asdf", "zxcv"],
  "array": [1, "2", 3],
  "arraywithsubs": [{"subkeyone": 1},
  "bignum": 9223372036854775807,
  "string": "simplejson",
  "bool": true
 }
 }`))
 if err != nil {
  panic("json format error")
 }
 //Get a field value s, err := ("test").Get("string").String()
 if err != nil {
  panic(err)
 }
 (s)
 //Check whether a field exists _, ok := ("test").CheckGet("string2")
 if ok {
  ("exist!")
 } else {
  ("Not exists")
 }

(2)interface

For example, there are two types of JSON:

{"Type":"sound","Msg":{"Description":"dynamite","Authority":"the Bruce Dickinson"}}
{"Type":"cowbell","Msg":{"More":true}}

Msg is a map[string]interface{}:

type Envelope struct {
 Type string
 Msg interface{}
}

var env Envelope
if err := ([]byte(input), &env); err != nil {
  (err)
 }
// for the love of Gopher DO NOT DO THIS
var desc string = .(map[string]interface{})["description"].(string)
(desc)

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.