使用Go语言解析动态JSON格式的方法
来源:脚本之家
时间:2022-12-23 08:54:56 346浏览 收藏
本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《使用Go语言解析动态JSON格式的方法》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~
通常使用Golang encoding/json 标准库可以方便的编码/解析JSON数据,但是前提需要定义struct数据结构。特别是解析未知结构的JSON数据时,原有方法很难满足需求了,本文主要介绍动态解析JSON格式。
Go语言的JSON 库
Go语言自带的JSON转换库为 encoding/json
1.1)其中把对象转换为JSON的方法(函数)为 json.Marshal(),其函数原型如下
func Marshal(v interface{}) ([]byte, error)
也就是说,这个函数接收任意类型的数据 v,并转换为字节数组类型,返回值就是我们想要的JSON数据和一个错误代码。当转换成功的时候,这个错误代码为nil
在进行对象转换为 JSON 的过程中,会遵循如下几条规则:
- 布尔型转换为 JSON 后仍是布尔型 , 如true -> true
- 浮点型和整数型转换后为JSON里面的常规数字,如 1.23 -> 1.23
- 字符串将以UTF-8编码转化输出为Unicode字符集的字符串,特殊字符比如
- 数组和切片被转换为JSON 里面的数组,[]byte类会被转换为base64编码后的字符串,slice的零值被转换为null
- 结构体会转化为JSON对象,并且只有结构体里边以大写字母开头的可被导出的字段才会被转化输出,而这些可导出的字段会作为JSON对象的字符串索引
- 转化一个map 类型的数据结构时,该数据的类型必须是 map[string]T(T 可以是encoding/json 包支持的任意数据类型)
1.2)把 JSON 转换回对象的方法(函数)为 json.Unmarshal(),其函数原型如下
func Unmarshal(data [] byte, v interface{}) 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 数据结构如下:
type User struct { Name string `json:"name"` Age int `json:"age"` }
在定义struct字段的时候,可以在字段后面添加tag,来控制encode/decode的过程:是否要 decode/encode 某个字段,JSON 中的字段名称是什么。字段名首字母控制字段的可见性,若要输出到JSON,首字母需要大写。
三种tag:
-
:不要解析这个字段
omitempty
:当字段为空(默认值)时,不要解析这个字段。比如 false、0、nil、长度为 0 的 array,map,slice,string
FieldName
:当解析 json 的时候,使用这个名字
举例来说吧:
// 解析的时候忽略该字段。默认情况下会解析这个字段,因为它是大写字母开头的 Field int `json:"-"` // 解析(encode/decode) 的时候,使用 `other_name`,而不是 `Field` Field int `json:"other_name"` // 解析的时候使用 `other_name`,如果struct 中这个值为空,就忽略它 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 就是 []byte 类型的数组,里面包含了解析为 JSON 之后的数据,可以使用string(data)转型为string。
(2)decode
要把JSON数据转换成Go类型的值(Decode),可以使用 json.Unmarshal 。
var user User err = json.Unmarshal(data, &user) if err != nil { fmt.Errorf("Can not decode data: %v\n", err) }
2、动态解析
动态JSON结构未知,若使用前面方法需要事先定义数据结构,这与PHP/Python JSON处理非常不同。若不考虑性能,使用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 } }`)) if err != nil { panic("json format error") } //获取某个字段值 s, err := js.Get("test").Get("string").String() if err != nil { panic(err) } fmt.Println(s) //检查某个字段是否存在 _, ok := js.Get("test").CheckGet("string2") if ok { fmt.Println("存在!") } else { fmt.Println("不存在") }
(2)interface
比如JSON有以下两种类型:
{"Type":"sound","Msg":{"Description":"dynamite","Authority":"the Bruce Dickinson"}} {"Type":"cowbell","Msg":{"More":true}}
Msg 具体什么类型实现无法判断, 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)
以上就是《使用Go语言解析动态JSON格式的方法》的详细内容,更多关于golang的资料请关注golang学习网公众号!
-
505 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
438 收藏
-
266 收藏
-
173 收藏
-
240 收藏
-
161 收藏
-
139 收藏
-
389 收藏
-
275 收藏
-
232 收藏
-
221 收藏
-
402 收藏
-
487 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 过时的歌曲
- 好细啊,收藏了,感谢老哥的这篇文章内容,我会继续支持!
- 2023-04-11 01:45:30
-
- 稳重的鸡翅
- 这篇文章出现的刚刚好,太全面了,很棒,码起来,关注作者大大了!希望作者大大能多写Golang相关的文章。
- 2023-04-04 22:45:49
-
- 聪明的铃铛
- 很详细,已加入收藏夹了,感谢楼主的这篇文章,我会继续支持!
- 2023-03-25 01:38:28
-
- 精明的嚓茶
- 真优秀,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢楼主分享文章内容!
- 2023-03-24 05:27:34
-
- 老实的汉堡
- 这篇文章太及时了,作者大大加油!
- 2023-03-01 02:13:50
-
- 稳重的鸡翅
- 很有用,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢博主分享文章!
- 2023-02-28 03:55:51
-
- 要减肥的唇膏
- 这篇技术贴出现的刚刚好,太细致了,感谢大佬分享,已收藏,关注师傅了!希望师傅能多写Golang相关的文章。
- 2023-02-22 23:20:51
-
- 眯眯眼的热狗
- 这篇文章内容真及时,作者大大加油!
- 2023-01-06 13:27:29
-
- 壮观的面包
- 这篇文章太及时了,很详细,受益颇多,mark,关注大佬了!希望大佬能多写Golang相关的文章。
- 2022-12-24 21:30:21