JSON 语言定义的内容非常简洁,主要分为三种类型:对象(object)、数组(array)和基本类型(value)。基本类型(value)包括:
jsoniter(json-iterator)是一款快且灵活的 JSON 解析器,同时提供 Java 和 Go 两个版本。从 dsljson 和 jsonparser 借鉴了大量代码。
jsoniter 的 Golang 版本可以比标准库(encoding/json)快 6 倍之多,而且这个性能是在不使用代码生成的前提下获得的。
[root@localhost web]# go get github.com/json-iterator/go
使用 go run testjson.go 运行该文件即可
package main
import (
"os"
"fmt"
"bytes"
"reflect"
"encoding/json"
"github.com/json-iterator/go"
)
func main() {
testjsonencode()
testjsondecode()
testunknowjsondecode()
testjsontag()
userrequester()
testjsoniter()
teststructjson()
testjsonnum()
jsonstr := []byte(`{"jsonrpc":"2.0","result":[{"host":"10297"}]}`)
fmt.Println("usestruct")
usestruct(jsonstr)
fmt.Println()
fmt.Println("notusestruct")
notusestruct(jsonstr)
jsonendecode()
}
type Animal struct {
Name string `json:"name"`
Weight string `json:"weight"`
}
//构造体 转 json字符串
func testjsonencode(){
var animals []Animal
animals = append(animals,Animal{Name:"Elephant",Weight:"3 ton"})
animals = append(animals,Animal{Name:"Whale",Weight:"10 ton"})
jsonstr,err := json.Marshal(animals)
if(err != nil){
fmt.Println("error:%v\n",err)
}
fmt.Println(string(jsonstr))
}
//字符串 转 json
func testjsondecode(){
var jsonstr = []byte(`[
{"Name":"李四","Weight":"45kg"},
{"Name":"张三","Weight":"88kg"}
]`)
var people []Animal
err := json.Unmarshal(jsonstr,&people)
if(err != nil){
fmt.Println("error:%v\n",err)
}
for key,val := range people{
fmt.Printf("people的key是%v val是%+v\n", key,val)
getType := reflect.TypeOf(val)
fmt.Println("get Type is :", getType.Name())
getValue := reflect.ValueOf(val)
fmt.Println("get all Fields is:", getValue)
// 获取方法字段
// 1. 先获取interface的reflect.Type,然后通过NumField进行遍历
// 2. 再通过reflect.Type的Field获取其Field
// 3. 最后通过Field的Interface()得到对应的value
for i := 0; i < getType.NumField(); i++ {
field := getType.Field(i)
value := getValue.Field(i).Interface()
fmt.Printf("%s: %v = %v\n", field.Name, field.Type, value)
}
println()
}
}
//未知的json 解析
func testunknowjsondecode(){
//在解析 JSON 的时候,任意动态的内容都可以解析成 interface{}。
var unknow interface{}
jsonstr := []byte(`{"Name":"hello","Sex":1,"parents":["Whale","Elaphant"]}`)
json.Unmarshal(jsonstr,&unknow)
for key,val := range unknow.(map[string]interface{}){
switch va := val.(type) { //判断 unknow下级的类型
case string:
fmt.Println(key," is string ",va)
case int:
fmt.Println(key, "is int ", va)
case float64:
fmt.Println(key, "is float64 ", va)
case []interface{}:
fmt.Println(key, "is array:")
for i, j := range va {
fmt.Println(i, j)
}
}
}
println()
}
//-----------------------------------------------------------------
/*
json tag 有很多值可以取,同时有着不同的含义,比如:
-:不要解析这个字段,表示该字段不会输出到 JSON
omitempty 当字段为空(默认值)时,不要解析这个字段。比如 false、0、nil、长度为 0 的 array,map,slice,string,就不会输出到JSON 串中
FieldName,当解析 json 的时候,使用这个名字
,string当字段类型是 bool, string, int, int64 等,而 tag 中带有该选项时,那么该字段在输出到 JSON 时,会把该字段对应的值转换成 JSON 字符串.
----------------------------
示例:
// 解析的时候忽略该字段。默认情况下会解析这个字段,因为它是大写字母开头的
Field int `json:"-"`
// 解析(encode/decode) 的时候,使用 `other_name`,而不是 `Field`
Field int `json:"other_name"`
// 解析的时候使用 `other_name`,如果struct 中这个值为空,就忽略它
Field int `json:"other_name,omitempty"`
// 解析的时候会将接受到的字符串类型转为int类型
Field int `json:"other_name,string"`
*/
type People struct {
Name string `json:"-"`
Age int `json:"age"` //注意 取别名不能使用中文
Sex int `json:"sex,omitempty"`
Weight int `json:"weight,string"`
}
func testjsontag(){
var people1 []People //二维数组
var people2 People //一维数组
var jsonstr []byte
var err error
jsonstr = []byte(`[
{"Name":"张三","Age":111,"Sex":2,"Weight":"46"}
]`)
err = json.Unmarshal(jsonstr,&people1)
fmt.Printf("err是%v\n", err)
fmt.Printf("people1是%+v\n", people1) //忽略了 Name属性
// 获取tag中的内容
t := reflect.TypeOf(people1)
field := t.Elem().Field(0)
fmt.Println(field.Tag)
fmt.Println(field.Tag.Get("json"))
jsonstr = []byte(`{
"Name":"李四",
"Age":666,
"Sex":0,
"Weight":"33"
}`)
err = json.Unmarshal(jsonstr,&people2)
fmt.Printf("err是%v\n", err)
fmt.Printf("people2是%+v\n", people2)
println()
}
//自定义解析方法
/*
// Marshaler 接口定义了怎么把某个类型 encode 成 JSON 数据
type Marshaler interface {
MarshalJSON() ([]byte, error)
}
// Unmarshaler 接口定义了怎么把 JSON 数据 decode 成特定的类型数据。如果后续还要使用 JSON 数据,必须把数据拷贝一份
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
*/
type UserRequest struct {
Name string
Mail Mail
Phone Phone
}
type Mail struct {
Value string
}
type Phone struct {
Value string
}
func (mailer *Mail) MarshalJSON() (data []byte, err error){
if(mailer != nil){
data = []byte(mailer.Value)
}
return
}
func (mailer *Mail) UnmarshalJSON(data []byte) error{
//判断 data 中 ,是否含有 @
if(!bytes.Contains(data,[]byte("@"))){
return fmt.Errorf("mail format error")
}
mailer.Value = string(data)
fmt.Printf("current mail format\n")
return nil
}
func (phone *Phone) MarshalJSON() (data []byte,err error){
if(phone != nil){
data = []byte(phone.Value)
}
return
}
func (phone *Phone) UnmarshalJSON(data []byte) error{
//判断手机号码是否11位
if(len(data) != 11){
return fmt.Errorf("phone format error")
}
phone.Value = string(data)
fmt.Printf("current phone format\n")
return nil
}
func userrequester(){
user := UserRequest{}
user.Name = "Tellphone"
var err error
err = user.Mail.UnmarshalJSON([]byte("callmephone.com"))
if(err != nil){
fmt.Printf("%v\n", err)
}
err = user.Phone.UnmarshalJSON([]byte("1351234567"))
if(err != nil){
fmt.Printf("%v\n", err)
}
fmt.Printf("%s的邮箱是%s 电话是%s\n", user.Name,user.Mail,user.Phone)
err = user.Mail.UnmarshalJSON([]byte("[email protected]"))
if(err != nil){
fmt.Printf("%v\n", err)
}
err = user.Phone.UnmarshalJSON([]byte("13512345678"))
if(err != nil){
fmt.Printf("%v\n", err)
}
fmt.Printf("%s的邮箱是%s 电话是%s\n", user.Name,user.Mail,user.Phone)
println()
}
//Json的编码器和解码器
/*
json包提供了解码器和编码器类型,以支持读取和写入json数据流的常见操作。在该包中使用NewDecoder和NewEncoder函数包装io。
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
*/
func jsonendecode(){
//{"Name": "Platypus", "Order": "Monotremata"}
fmt.Printf("请输入json字符串:")
encoder := json.NewEncoder(os.Stdout)
decoder := json.NewDecoder(os.Stdin)
for{
var v map[string]interface{}
if err := decoder.Decode(&v);err != nil{
fmt.Println(err) //解析出错,打印错误信息
jsonendecode() //重新调用自身
return
}
for k := range v{
if k != "Name"{
delete(v,k)
}
}
if err := encoder.Encode(&v);err != nil{
fmt.Println(err)
}
}
}
//推荐的 json 解析库
//jsoniter(json-iterator)是一款快且灵活的 JSON 解析器,同时提供 Java 和 Go 两个版本。从 dsljson 和 jsonparser 借鉴了大量代码。
/*
基本用法如下:
jsoniter.Marshal(&data)
jsoniter.Unmarshal(input, &data)
*/
var testString = `{"Name": "Platypus", "Order": "Monotremata"}`
func testjsoniter(){
var animal interface{}
var err error
var jsonBlob = []byte(testString)
err = jsoniter.Unmarshal(jsonBlob,&animal)
if(err != nil){
fmt.Printf("error %v\n",err)
}
fmt.Printf("animal的值是%v\n", animal)
}
//复合结构的解析
type Car struct {
Name string
Engine Engine
Tire Tire
}
type Engine struct {
Value string
}
type Tire struct {
Value string
}
func teststructjson(){
var jsonstr = []byte(`{"Name":"奔驰","Engine":{"Value":"自由梦"},"Tire":{"Value":"米其林"}}`)
car := Car{}
var engine Engine
var tire Tire
jsoniter.Unmarshal(jsonstr,&struct {
*Car
*Engine
*Tire
}{&car,&engine,&tire})
fmt.Printf("%+v\n",car)
fmt.Printf("小明从小红的%v上卸下了%v发动机用来改造他的车,连%v轮胎都不放过,真实孤终生啊!\n",car.Name,car.Engine.Value,car.Tire.Value)
}
//Unmarshal 精度问题
//golang使用json.Unmarshal的时候,有些数字类型的数据会默认转为float64,而一些数据因其比较大,导致输出的时候会出现数据与原数据不等的现象,解决办法是,将此数据类型变为json.Number
type Numb struct {
Nid jsoniter.Number `json:"nid"`
}
func testjsonnum(){
var jsonstr = `{"nid":114420234065740369922}`
var number Numb
jsoniter.Unmarshal([]byte(jsonstr),&number)
fmt.Printf("使用Number转换前 %+v\n", number)
fmt.Printf("使用Number转换后 %+v\n", number.Nid.String())
}
//自定义json 解析
type ResultStruct struct {
Jsonrpc string `json:"jsonrpc"`
Result []HostStruct `json:"result"`
}
type HostStruct struct {
Host string `json:"host"`
}
func usestruct(jsonstr []byte){
var res ResultStruct
err := json.Unmarshal(jsonstr,&res)
if(err != nil){
fmt.Printf("error:%v\n",err)
}
fmt.Printf("res: %+v\n", res)
}
func notusestruct(jsonstr []byte){
var unknow interface{}
json.Unmarshal(jsonstr,&unknow)
reprinln(unknow)
}
func reprinln(unknow interface{}){
for key,val := range unknow.(map[string]interface{}){
switch va := val.(type) { //判断 unknow下级的类型
case string:
fmt.Println(key," is string ",va)
case int:
fmt.Println(key, "is int ", va)
case float64:
fmt.Println(key, "is float64 ", va)
case []interface{}:
fmt.Println(key, "is array:")
for i, val := range va {
fmt.Println(i, val)
reprinln(val)
}
}
}
}
使用 go run testjson2.go 运行该文件即可
package main
import (
"encoding/json"
"fmt"
)
type Server struct {
ServerName string `json:"servername"`
ServerIP string `json:"serverip"`
}
type Serverslice struct {
Servers []Server `json:"servers"`
}
func main() {
//已知数据类型的json解析
fmt.Println("testdecodejson")
testdecodejson()
//未知数据类型的json解析
fmt.Println()
fmt.Println("testdecodejson2")
testdecodejson2()
//转换成json字符串
fmt.Println()
fmt.Println("testencodejson")
testencodejson()
//json构造体的其他用法
fmt.Println()
fmt.Println("structother")
structother()
}
func testdecodejson(){
var s Serverslice
str := `{
"servers":[
{
"serverName":"Shanghai_VPN",
"serverIP":"127.0.0.1"
},
{
"serverName":"Beijing_VPN",
"serverIP":"127.0.0.2"
}
]
}`
json.Unmarshal([]byte(str),&s)
fmt.Println(s)
}
func testdecodejson2(){
b := []byte(`{
"Name":"wednesday",
"Age":6,
"parents":["gomez","morticia"]
}`)
var f interface{}
err := json.Unmarshal(b,&f)
if err != nil{
fmt.Println(err)
return
}
m := f.(map[string]interface{})
for k,v := range m{
switch vv := v.(type){
case string:
fmt.Println(k,"is string",vv)
case int:
fmt.Println(k,"is int",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 do not know how to handle")
}
}
}
func testencodejson(){
/*
Marshal函数只有在转换成功的时候才会返回数据,在转换的过程中我们需要注意几点:
·JSON对象只支持string作为key,所以要编码一个map,那么必须是map[string]T这种类型(T是Go语言中任意的类型)
·Channel, complex和function是不能被编码成JSON的
·嵌套的数据是不能编码的,不然会让JSON编码进入死循环
·指针在编码的时候会输出指针指向的内容,而空指针会输出null
*/
var s Serverslice
s.Servers = append(s.Servers,Server{ServerName:"shanghai_",ServerIP:"127.0.0.1"})
s.Servers = append(s.Servers,Server{ServerName:"beijing_",ServerIP:"127.0.0.2"})
b,err := json.Marshal(s)
if err != nil{
fmt.Println("json err: ",err)
}
fmt.Println(string(b))
}
/*
·字段的tag 是 "-" , 那么这个字段不会输出到json
·tag 中带有自定义的名称,那么这个自定义名称会出现在json的字段名中,例如上面例子中的serverName
·tag 中如果带有 "omitempty" 选项,那么如果该字段值为空,就不会输出到json串中
·如果字段类型是bool,string,int,int64等,而tag中带有",string"选项,那么这个字段在输出到json的时候回把该字段对应的值转换成json字符串
*/
type ServerOther struct {
//ID不会导出在json中
ID int `json:"-"`
//ServerName2 的值会进行二次json编码
ServerName string `json:"serverName"`
ServerName2 string `json:"serverName2,string"`
//如果ServerIP 为空,则不会输出到json串中
ServerIP string `json:"serverIP,omitempty"`
}
func structother(){
s := ServerOther{
ID:3,
ServerName:`GO "1.13"`,
ServerName2:`GO "1.13"`,
ServerIP:``,
}
b,_ := json.Marshal(s)
fmt.Printf("serverother: %s\n",b)
}
json参考:https://www.cnblogs.com/Survivalist/articles/10439083.html
参考:https://www.golang123.com/book/9?chapterID=179