
离线 TA的专栏
- 打卡等级:即来则安
- 打卡总天数:15
- 打卡月天数:0
- 打卡总奖励:227
- 最近打卡:2023-08-27 04:04:57
|
目录
- 前言
- 什么是JSON
- 如何在Go中解析不确定的JSON数据
- 通过看文档的方式去确定对应的JSON数据,然后构造对应的结构体
- map[string] interface{}
- 第三方库
- json.RawMessage与json.Number
- 最后
前言
在开发中常常会碰到很多JSON类型的数据进行交互,而其中有很多JSON数据你是不能确定它的字段和结构的,而Go语言是一门静态强类型的语言,在进行JSON解析的时候必须要确定字段的类型,定义出对应的结构体,然后再进行Unmarshal,那这二者之间的冲突我们该如何解决呢?
什么是JSON
- json是JavaScript Object Notation(JavaScript对象表示法)
- json是轻量级的文本数据交换格式
- json独立于语言
- json具有自我描述性,更容易理解
- json使用js语法来描述数据对象,但是json仍然独立于语言和平台,json解析器和json库支持许多不同的编程语言
json是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,之所以json这么流行,是因为json的结构和多级结构体(对象)刚好能对应上,并且本身也十分易读。而前后端交互的时候后端通常会返回给前端一个多级的结构体,于是json慢慢开始流行了,且json是跨语言和跨平台的,自身也足够轻量级。
json的几种标准格式 - 一个标准的json数据
- //每个key对应的是一个value
- {
- “k1": 1,
- "k2": 2 //注意结尾的这个不能有逗号
- }
- json字符串
- {
- "k1": "1",
- "k2": "2"
- }
- json数组
- {
- “k1”: [1,2],
- “k2”: [3,4]
- }
- json对象
- {
- “k1”: {“1”: “haihai”},
- “k2”: {“2”:”haihahai”}
- }
- json对象数组
- {
- “k1”: [
- {“k11”: “hellohello”},
- {“k12”: “badbad”}
- ]
- }
- json数组对象
- {
- “k2”: {
- “hello”: [1,2,3]
- }
- }
- 所有的JSON数据都是由上述几种JSON数据组合而成
复制代码 如何在Go中解析不确定的JSON数据
通过看文档的方式去确定对应的JSON数据,然后构造对应的结构体
这是最靠谱的方式,最合理也是效率最高的方式。 - // 请求其他服务
- jsonStr := xxx
- var data interface{}
- err := json.Unmarshal([]byte(jsonStr),&data)
- fmt.Println(data)
复制代码比如可以先拿一个interface{}类型来接住JSON数据,然后看这个interface{}的值,来确定这个JSON数据哪些字段是string 哪些是object 哪些是int float等等
当然这也不是完全适用的,比如下面这种情况,有一个字段如下
type : []
能看出来type是一个切片类型的值,但是具体的类型你并不知道,可能是[]int 也有可能是[]string []float等等
map[string] interface{}
这个类型是map键值对,值可以是任意类型,因为在go中任意类型都实现了空接口interface{},而json数据也是key value的键值对,所以map[string] interface{}天然支持解析json类型数据 - jsonStr := xxx
- var data map[string]interface{}
- err := json.Unmarshal([]byte(jsonStr),&data)
- // 你想取的字段
- fieldValue := data["field"]
- // 类型断言
- if value,ok := data["field"].(float64);ok {
- } else if vluae,ok := data["field"].(int64); ok {
- }
- 理论上所有的合法的JSON数据都可以被反序列化到map[string]interface{}中
- 但是实际应用中 可能会出现一些无法被map[string]interface{}解析的JSON数据
复制代码
- JSON 数据中包含了多层嵌套的数据结构。在这种情况下,如果没有使用递归或者其他方式对嵌套数据进行处理,可能会导致反序列化失败。
- JSON 数据中包含了数组类型,但是数组元素类型不一致或者无法转换成相应的类型。在这种情况下,可能需要手动处理数组元素或者使用其他数据类型来保存数组数据。
- JSON 数据中包含了自定义数据类型或者复杂的数据结构,无法使用 map[string]interface{} 类型来反序列化。在这种情况下,需要定义相应的结构体或者使用其他适合的数据类型来反序列化。
第三方库
除了encoding/json之外,还有很多第三方库可以用来解析不确定的JSON数据,例如gjson和jsonparser,这些库通常提供了更加灵活和高效的JSON解析方式,可以根据具体的需求选择合适的库来使用
json.RawMessage与json.Number
- json.RawMessage 是一个非常高效的数据类型,因为她不需要进行任何解析和类型转换,直接保存了未经处理的原始JSON数据,在反序列化的时候只需要将转化为对应的数据类型即可,无需重新解析JSON数据
- json.Number 表示JSON中的数字类型,可以用来保存任意精度的数字。这个数字可以特别大,可能会无法用Go中的整数或者浮点数来表示
- package main
- import (
- "encoding/json"
- "fmt"
- )
- func main() {
- jsonData := []byte(`{
- "id": 12345,
- "name": "John Doe",
- "age": 30,
- "score": 95.5,
- "is_student": true,
- "tags": ["tag1", "tag2", "tag3"],
- "extra": {
- "field1": "value1",
- "field2": 123
- }
- }`)
- var m map[string]json.RawMessage
- err := json.Unmarshal(jsonData, &m)
- if err != nil {
- panic(err)
- }
- var id int
- err = json.Unmarshal(m["id"], &id)
- if err != nil {
- panic(err)
- }
- fmt.Printf("id: %d\n", id)
- var name string
- err = json.Unmarshal(m["name"], &name)
- if err != nil {
- panic(err)
- }
- fmt.Printf("name: %s\n", name)
- var age int
- err = json.Unmarshal(m["age"], &age)
- if err != nil {
- panic(err)
- }
- fmt.Printf("age: %d\n", age)
- var score float64
- err = json.Unmarshal(m["score"], &score)
- if err != nil {
- panic(err)
- }
- fmt.Printf("score: %f\n", score)
- var isStudent bool
- err = json.Unmarshal(m["is_student"], &isStudent)
- if err != nil {
- panic(err)
- }
- fmt.Printf("is_student: %v\n", isStudent)
- var tags []string
- err = json.Unmarshal(m["tags"], &tags)
- if err != nil {
- panic(err)
- }
- fmt.Printf("tags: %v\n", tags)
- var extra map[string]json.RawMessage
- err = json.Unmarshal(m["extra"], &extra)
- if err != nil {
- panic(err)
- }
- var field1 string
- err = json.Unmarshal(extra["field1"], &field1)
- if err != nil {
- panic(err)
- }
- fmt.Printf("extra.field1: %s\n", field1)
- var field2 int
- err = json.Unmarshal(extra["field2"], &field2)
- if err != nil {
- panic(err)
- }
- fmt.Printf("extra.field2: %d\n", field2)
- }
- // 不确定的类型
- data := make(map[string]interface{})
- if err := json.Unmarshal(rawData, &data); err != nil {
- log.Fatal(err)
- }
- if value, ok := data["age"].(float64); ok {
- // 处理年龄为浮点数的情况
- } else if value, ok := data["age"].(int); ok {
- // 处理年龄为整数的情况
- } else {
- // 处理年龄为其他类型或不存在的情况
- }
复制代码需要注意的是:类型断言的底层为反射,因为在运行时需要判断一个接口值的具体类型,而这个类型是在编译时无法确定的,需要在运行时动态地获取。效率比正常的代码低一到两个数量级,而且需要消耗额外的时间和内存。
最后
以上就是Go解析不定JSON数据的方法详解的详细内容,更多关于Go解析不定JSON数据的资料请关注晓枫资讯其它相关文章!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:  进行删除处理。
4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
|