Use the Go language to resolve methods in dynamic JSON format

  • 2020-06-12 09:18:20
  • OfStack

The Golang encoding/json standard library is often used to easily encode/parse JSON data, but the struct data structure needs to be defined. In particular, when analyzing JSON data with unknown structure, the original method can hardly meet the requirements. This paper mainly introduces the dynamic parsing JSON format.

JSON library for the Go language

Go language comes with JSON conversion library for encoding/json

The method (function) to convert the object to JSON is json. Marshal(), and its function prototype is as follows

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

In other words, this function takes any type of data, v, and converts it to a byte array type, with the return value being the desired JSON data and 1 error code. When the conversion succeeds, the error code is nil

There are a few rules for converting objects to JSON:

A Boolean is still a Boolean when converted to JSON, such as true - > true Floating-point and integer values are converted to regular JSON Numbers, such as 1.23 - > 1.23 String will be converted to Unicode character set in UTF-8 encoding, special characters such as < Will be escaped as \u003c Arrays and slices are converted to arrays within JSON, the []byte class is converted to base64 encoded strings, and the zero value of slice is converted to null The structure is converted to an JSON object, and only exportable fields that begin with an uppercase letter inside the structure are output, and these exportable fields are used as a string index for the JSON object When converting a data structure of type map, the data must be of type 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 json.Unmarshal (), and its function prototype is as follows

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

This function parses the data passed in as an JSON, and the parsed data is stored in the parameter v. The argument v is also of any type (but 1 must be a pointer to a type), because when we parse JSON with this function, the function does not know the type of the argument passed in, so it needs to receive all types.

So, what happens if JSON doesn't match the structure of the object when parsing, which requires the parsing function json.Unmarshal () to follow these rules

The json. Unmarshal() function looks for fields in the target structure in one agreed order, and if one is found, a match occurs. So what is found? Here's another rule for "found" : If an JSON object has an index named "Foo", to populate the target field of the target structure with the corresponding value of "Foo", json.Unmarshal () will look for matches in the following order

§ 1 field containing the Foo tag § 1 field named Foo § A field named Foo or Foo, or Foo except for the initial, is case-insensitive. These fields must all begin with an uppercase letter in the type declaration and be exportable.

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

When the structure of JSON is unknown, the following rules apply:

The Boolean value in § JSON is converted to type bool in Go § The value is converted to type float64 in Go § String converted to string § JSON array is converted to []interface{} type § JSON objects are converted to map[string]interface{} type The § null value is converted to nil

Note: In Go's standard library encoding/json package, map[string]interface{} and []interface{} types are allowed to store JSON objects or arrays of unknown structure, respectively

1. Traditional methods

For example, User data structure is as follows:


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

When defining the struct field, you can add tag to the end of the field to control the process of encode/decode: whether a field is to be decode/encode and what the field name is in JSON. The first letter of the field name controls the visibility of the field. To output to JSON, the first letter needs to be capitalized.

Three kinds of tag:

- : Do not parse this field

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

FieldName : Use this name when parsing json

For example:


//  Ignore this field when parsing. This field is resolved by default because it begins with an uppercase letter 
Field int `json:"-"`
//  Resolution ( encode/decode )   "  `other_name` Rather than  `Field`
Field int `json:"other_name"`
//  When parsing  `other_name` If the struct  If this value is null, ignore it 
Field int `json:"other_name,omitempty"`

(1) encode


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

data is an array of type []byte containing data parsed to JSON, which can be converted to string using string(data).

(2) decode

To convert the JSON data to a value of type Go (Decode), use json.Unmarshal.


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

2. Dynamic analysis

The dynamic JSON structure is unknown, and using the previous method requires defining the data structure in advance, which is very different from the PHP/Python JSON processing. simplejson is used regardless of performance.

(1) simplejson


js, err := simplejson.NewJson([]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")
 }
 // Gets the value of a field 
 s, err := js.Get("test").Get("string").String()
 if err != nil {
  panic(err)
 }
 fmt.Println(s)
 // Check if a field exists 
 _, ok := js.Get("test").CheckGet("string2")
 if ok {
  fmt.Println(" There! ")
 } else {
  fmt.Println(" There is no ")
 }

(2) interface

JSON, for example, has two types:


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

Msg being a map[string]interface{}


type Envelope struct {
 Type string
 Msg interface{}
}

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

Related articles: