使用Go语言解析动态JSON格式的方法
通常使用Golangencoding/json标准库可以方便的编码/解析JSON数据,但是前提需要定义struct数据结构。特别是解析未知结构的JSON数据时,原有方法很难满足需求了,本文主要介绍动态解析JSON格式。
Go语言的JSON库
Go语言自带的JSON转换库为encoding/json
1.1)其中把对象转换为JSON的方法(函数)为json.Marshal(),其函数原型如下
funcMarshal(v interface{})([]byte,error)
也就是说,这个函数接收任意类型的数据v,并转换为字节数组类型,返回值就是我们想要的JSON数据和一个错误代码。当转换成功的时候,这个错误代码为nil
在进行对象转换为JSON的过程中,会遵循如下几条规则:
- 布尔型转换为JSON后仍是布尔型,如true->true
- 浮点型和整数型转换后为JSON里面的常规数字,如1.23->1.23
- 字符串将以UTF-8编码转化输出为Unicode字符集的字符串,特殊字符比如<将会被转义为\u003c
- 数组和切片被转换为JSON里面的数组,[]byte类会被转换为base64编码后的字符串,slice的零值被转换为null
- 结构体会转化为JSON对象,并且只有结构体里边以大写字母开头的可被导出的字段才会被转化输出,而这些可导出的字段会作为JSON对象的字符串索引
- 转化一个map类型的数据结构时,该数据的类型必须是map[string]T(T可以是encoding/json包支持的任意数据类型)
1.2)把JSON转换回对象的方法(函数)为json.Unmarshal(),其函数原型如下
funcUnmarshal(data[]byte,vinterface{})error
这个函数会把传入的data作为一个JSON来进行解析,解析后的数据存储在参数v中。这个参数v也是任意类型的参数(但一定是一个类型的指针),原因是我们在是以此函数进行JSON解析的时候,这个函数不知道这个传入参数的具体类型,所以它需要接收所有的类型。
那么,在进行解析的时候,如果JSON和对象的结构不对口会发生什么呢,这就需要解析函数json.Unmarshal()遵循以下规则
json.Unmarshal()函数会根据一个约定的顺序查找目标结构中的字段,如果找到一个即发生匹配。那什么是找到了呢?关于“找到了”又有如下的规则:假设一个JSON对象有个名为"Foo"的索引,要将"Foo"所对应的值填充到目标结构体的目标字段上,json.Unmarshal()将会遵循如下顺序进行查找匹配
- §一个包含Foo标签的字段
- § 一个名为Foo的字段
- §一个名为Foo或者Foo或者除了首字母其他字母不区分大小写的名为Foo的字段。这些字段在类型声明中必须都是以大写字母开头、可被导出的字段。
注意:如果JSON中的字段在Go目标类型中不存在,json.Unmarshal()函数在解码过程中会丢弃该字段。
当JSON的结构是未知的时候,会遵循如下规则:
- §JSON中的布尔值将会转换为Go中的bool类型
- §数值会被转换为Go中的float64类型
- §字符串转换后还是string类型
- §JSON数组会转换为[]interface{}类型
- §JSON对象会转换为map[string]interface{}类型
- §null值会转换为nil
注意:在Go的标准库encoding/json包中,允许使用map[string]interface{}和[]interface{}类型的值来分别存放未知结构的JSON对象或数组
1、传统方法
比如User数据结构如下:
typeUserstruct{ Namestring`json:"name"` Ageint`json:"age"` }
在定义struct字段的时候,可以在字段后面添加tag,来控制encode/decode的过程:是否要decode/encode某个字段,JSON中的字段名称是什么。字段名首字母控制字段的可见性,若要输出到JSON,首字母需要大写。
三种tag:
-:不要解析这个字段
omitempty:当字段为空(默认值)时,不要解析这个字段。比如false、0、nil、长度为0的array,map,slice,string
FieldName:当解析json的时候,使用这个名字
举例来说吧:
//解析的时候忽略该字段。默认情况下会解析这个字段,因为它是大写字母开头的 Fieldint`json:"-"` //解析(encode/decode)的时候,使用`other_name`,而不是`Field` Fieldint`json:"other_name"` //解析的时候使用`other_name`,如果struct中这个值为空,就忽略它 Fieldint`json:"other_name,omitempty"`
(1)encode
user:=User{Name:"test",Age:23} data,err:=json.Marshal(user) iferr!=nil{ fmt.Println(string(data)) }
data就是[]byte类型的数组,里面包含了解析为JSON之后的数据,可以使用string(data)转型为string。
(2)decode
要把JSON数据转换成Go类型的值(Decode),可以使用json.Unmarshal。
varuserUser err=json.Unmarshal(data,&user) iferr!=nil{ fmt.Errorf("Cannotdecodedata:%v\n",err) }
2、动态解析
动态JSON结构未知,若使用前面方法需要事先定义数据结构,这与PHP/PythonJSON处理非常不同。若不考虑性能,使用simplejson。
(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 } }`)) iferr!=nil{ panic("jsonformaterror") } //获取某个字段值 s,err:=js.Get("test").Get("string").String() iferr!=nil{ panic(err) } fmt.Println(s) //检查某个字段是否存在 _,ok:=js.Get("test").CheckGet("string2") ifok{ fmt.Println("存在!") }else{ fmt.Println("不存在") }
(2)interface
比如JSON有以下两种类型:
{"Type":"sound","Msg":{"Description":"dynamite","Authority":"theBruceDickinson"}} {"Type":"cowbell","Msg":{"More":true}}
Msg具体什么类型实现无法判断,Msgbeingamap[string]interface{}:
typeEnvelopestruct{ Typestring Msginterface{} } varenvEnvelope iferr:=json.Unmarshal([]byte(input),&env);err!=nil{ log.Fatal(err) } //fortheloveofGopherDONOTDOTHIS vardescstring=env.Msg.(map[string]interface{})["description"].(string) fmt.Println(desc)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。