Go怎么解析不定JSON数据?

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
简介: 在Go中处理不确定结构的JSON数据,可以使用`map[string]interface{}`来解析,它能适应各种JSON键值对,但需要类型检查。另一种方法是使用`json.RawMessage`保存原始JSON,之后按需解析。此外,`json.Number`用于处理任意精度的数字。当JSON字段类型未知时,可以先解码到`interface{}`并做类型断言。第三方库如gjson和jsonparser提供更灵活的解析选项。

前言

在开发中常常会碰到很多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的几种标准格式

css

复制代码

一个标准的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数据,然后构造对应的结构体

这是最靠谱的方式,最合理也是效率最高的方式。

go

复制代码

// 请求其他服务   
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类型数据

go

复制代码

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.RawMessage转化为对应的数据类型即可,无需重新解析JSON数据
  • json.Number 表示JSON中的数字类型,可以用来保存任意精度的数字。这个数字可以特别大,可能会无法用Go中的整数或者浮点数来表示

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 {
    // 处理年龄为其他类型或不存在的情况
}

需要注意的是:类型断言的底层为反射,因为在运行时需要判断一个接口值的具体类型,而这个类型是在编译时无法确定的,需要在运行时动态地获取。效率比正常的代码低一到两个数量级,而且需要消耗额外的时间和内存。


相关文章
|
25天前
|
数据采集 JSON 数据处理
抓取和分析JSON数据:使用Python构建数据处理管道
在大数据时代,电商网站如亚马逊、京东等成为数据采集的重要来源。本文介绍如何使用Python结合代理IP、多线程等技术,高效、隐秘地抓取并处理电商网站的JSON数据。通过爬虫代理服务,模拟真实用户行为,提升抓取效率和稳定性。示例代码展示了如何抓取亚马逊商品信息并进行解析。
抓取和分析JSON数据:使用Python构建数据处理管道
|
11天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
15天前
|
JSON 缓存 前端开发
PHP如何高效地处理JSON数据:从编码到解码
在现代Web开发中,JSON已成为数据交换的标准格式。本文探讨了PHP如何高效处理JSON数据,包括编码和解码的过程。通过简化数据结构、使用优化选项、缓存机制及合理设置解码参数等方法,可以显著提升JSON处理的性能,确保系统快速稳定运行。
|
8天前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索API接口返回数据的JSON格式示例
拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品,该接口返回的通常是一个JSON格式的响应,其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例,同时提供对其关键字段的解释
|
30天前
|
JSON JavaScript Java
在Java中处理JSON数据:Jackson与Gson库比较
本文介绍了JSON数据交换格式及其在Java中的应用,重点探讨了两个强大的JSON处理库——Jackson和Gson。文章详细讲解了Jackson库的核心功能,包括数据绑定、流式API和树模型,并通过示例演示了如何使用Jackson进行JSON解析和生成。最后,作者分享了一些实用的代码片段和使用技巧,帮助读者更好地理解和应用这些工具。
在Java中处理JSON数据:Jackson与Gson库比较
|
11天前
|
安全 测试技术 Go
Go语言中的并发编程模型解析####
在当今的软件开发领域,高效的并发处理能力是提升系统性能的关键。本文深入探讨了Go语言独特的并发编程模型——goroutines和channels,通过实例解析其工作原理、优势及最佳实践,旨在为开发者提供实用的Go语言并发编程指南。 ####
|
16天前
|
Go
|
1月前
|
JSON API 数据格式
商品详情数据JSON格式示例参考(api接口)
JSON数据格式的商品详情数据通常包含商品的多个层级信息,以下是一个综合多个来源信息的JSON数据格式的商品详情数据示例参考:
|
1月前
|
存储 JSON 前端开发
JSON与现代Web开发:数据交互的最佳选择
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也便于机器解析和生成。它以文本格式存储数据,常用于Web应用中的数据传输,尤其是在客户端和服务器之间。
44 0
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2

推荐镜像

更多