Golang的json解析--Gjson库的使用举例

目录

简介

安装

原生的json解析 

Gjson使用举例

基本使用

键路径

使用示例

其他资源

简介

在 Golang 中,解析 JSON 数据是一项非常常见的任务。Go提供了标准的JSON包,可以轻松地将JSON数据序列化和反序列化。但是,在使用标准JSON包解析大型复杂JSON结构时,可能存在些许不足,例如代码冗余,性能瓶颈等问题。针对这些问题,目前有许多优秀的JSON解析框架,GJSON是其中一个很不错的选择。

GJSON 是一个 Go 包,提供了一种 高效 和 简单 的方式来从 JSON 文档中提取值。它具有如 一行检索、点号路径语法、迭代 和 解析 JSON 行 等特性。

本文将详细讲解如何使用GJSON框架解析JSON数据。

安装

GJSON模块可以通过go get命令来安装。

go get -u github.com/tidwall/gjson

原生的json解析 

以解析豆瓣接口https://api.douban.com/v2/movie/new_movies,返回的数据如下:

{"subjects": [{"rating": {"max": 10,"average": 7.1,"details": {"1": 16.0,"3": 135.0,"2": 56.0,"5": 102.0,"4": 122.0},"stars": "35","min": 0},"genres": ["\u5267\u60c5","\u559c\u5267","\u52a8\u4f5c"],"title": "\u76df\u519b\u6562\u6b7b\u961f","casts": [{"avatars": {"small": "https://img9.doubanio.com\/view\/celebrity\/m\/public\/p1371934661.95.jpg","large": "https://img9.doubanio.com\/view\/celebrity\/m\/public\/p1371934661.95.jpg","medium": "https://img9.doubanio.com\/view\/celebrity\/m\/public\/p1371934661.95.jpg"},"name_en": "Henry Cavill","name": "\u4ea8\u5229\u00b7\u5361\u7ef4\u5c14","alt": "https:\/\/movie.douban.com\/celebrity\/1044713\/","id": "1044713"},{"avatars": {"small": "https://img3.doubanio.com\/view\/celebrity\/m\/public\/p1607496406.37.jpg","large": "https://img3.doubanio.com\/view\/celebrity\/m\/public\/p1607496406.37.jpg","medium": "https://img3.doubanio.com\/view\/celebrity\/m\/public\/p1607496406.37.jpg"},"name_en": "Eiza Gonz\u00e1lez","name": "\u827e\u838e\u00b7\u5188\u8428\u96f7\u65af","alt": "https:\/\/movie.douban.com\/celebrity\/1233270\/","id": "1233270"}],"durations": ["120\u5206\u949f"],"collect_count": 25322,"mainland_pubdate": "2024-05-24","has_video": false,"original_title": "The Ministry of Ungentlemanly Warfare","subtype": "movie","directors": [{"avatars": {"small": "https://img1.doubanio.com\/view\/celebrity\/m\/public\/p47189.jpg","large": "https://img1.doubanio.com\/view\/celebrity\/m\/public\/p47189.jpg","medium": "https://img1.doubanio.com\/view\/celebrity\/m\/public\/p47189.jpg"},"name_en": "Guy Ritchie","name": "\u76d6\u00b7\u91cc\u5947","alt": "https:\/\/movie.douban.com\/celebrity\/1025148\/","id": "1025148"}],"pubdates": ["2024-04-18(\u4e2d\u56fd\u9999\u6e2f)","2024-04-19(\u7f8e\u56fd)","2024-05-24(\u4e2d\u56fd\u5927\u9646)"],"year": "2024","images": {"small": "https://img9.doubanio.com\/view\/photo\/s_ratio_poster\/public\/p2908456064.jpg","large": "https://img9.doubanio.com\/view\/photo\/s_ratio_poster\/public\/p2908456064.jpg","medium": "https://img9.doubanio.com\/view\/photo\/s_ratio_poster\/public\/p2908456064.jpg"},"alt": "https:\/\/movie.douban.com\/subject\/34971728\/","id": "34971728"}],"title": "\u8c46\u74e3\u7535\u5f71\u65b0\u7247\u699c"
}

使用golang原始的方式,将响应体JSON反序列化为一个字典(map),以便于访问其中的数据。

body, err := io.ReadAll(res.Body)if err != nil {l.Errorf("Failed to read response body:", err)return nil, err}//格式化输出json//var str bytes.Buffer//_ = json.Indent(&str, []byte(body), "", "    ")//l.Debugf("formated: ", str.String())var keyVal map[string]interface{}err = json.Unmarshal(body, &keyVal)if err != nil {l.Errorf("Failed to extract key value:", err)}//l.Debug(keyValue)var hot types.HotItemvar responseData []types.HotItemlist_, ok := keyVal["subjects"].([]interface{})if ok {for _, item := range list_ {itemMap, ok := item.(map[string]interface{})if ok {//l.Debug(itemMap)hot.Id = itemMap["id"].(string)hot.Title = itemMap["title"].(string)tmp := itemMap["images"].(map[string]interface{})hot.Cover = l.svcCtx.Config.MvConf.Referer + tmp["small"].(string)hot.Rate = itemMap["rating"].(map[string]interface{})["average"].(float64)}responseData = append(responseData, hot)}}

 示例如下:

func (l *HotMovieLogic) HotMovie(req *types.HotMovieReq) (resp *types.HotMovieResp, err error) {// todo: add your logic here and delete this linetype Request struct {Req    types.HotMovieReqApiKey string `json:"apikey"`}req_ := Request{Req:    *req,ApiKey: l.svcCtx.Config.MvConf.ApiKey,}l.Debug(req_)url := l.svcCtx.Config.MvConf.BaseUrl + "/movie/in_theaters"res, err_ := httpc.Do(l.ctx, http.MethodPost, url, req_)if err_ != nil {l.Error(err_)return nil, err_}defer res.Body.Close()body, err := io.ReadAll(res.Body)if err != nil {l.Errorf("Failed to read response body:", err)return nil, err}//格式化输出json//var str bytes.Buffer//_ = json.Indent(&str, []byte(body), "", "    ")//l.Debugf("formated: ", str.String())var keyVal map[string]interface{}err = json.Unmarshal(body, &keyVal)if err != nil {l.Errorf("Failed to extract key value:", err)}//l.Debug(keyValue)var hot types.HotItemvar responseData []types.HotItemlist_, ok := keyVal["subjects"].([]interface{})if ok {for _, item := range list_ {itemMap, ok := item.(map[string]interface{})if ok {//l.Debug(itemMap)hot.Id = itemMap["id"].(string)hot.Title = itemMap["title"].(string)tmp := itemMap["images"].(map[string]interface{})hot.Cover = l.svcCtx.Config.MvConf.Referer + tmp["small"].(string)hot.Rate = itemMap["rating"].(map[string]interface{})["average"].(float64)}responseData = append(responseData, hot)}}//t := reflect.TypeOf(keyVal["count"])//l.Debugf("Type: %v\n", t)resp = &types.HotMovieResp{Code:    0,Message: res.Status,Data:    responseData,Count:   int(keyVal["count"].(float64)),Start:   int(keyVal["start"].(float64)),Total:   int(keyVal["total"].(float64)),Title:   keyVal["title"].(string),}return resp, nil
}

Gjson使用举例

基本使用

package mainimport ("fmt""github.com/tidwall/gjson"
)func main() {json := `{"name":{"first":"li","last":"dj"},"age":18}`lastName := gjson.Get(json, "name.last")fmt.Println("last name:", lastName.String())age := gjson.Get(json, "age")fmt.Println("age:", age.Int())email := gjson.Get(json, "email")// json 中不存在该字段时,String为空串,Int为0,即返回想要转换的类型的零值fmt.Println("email:", email.String())
}

使用很简单,只需要传入 JSON 串和要读取的键路径即可。注意一点细节,因为gjson.Get()函数实际上返回的是gjson.Result类型,我们要调用其相应的方法进行转换对应的类型。如上面的String()Int()方法。 

获取值

Get 函数搜索 JSON 中指定的路径。路径以点号分隔,如 "name.last" 或 "age"。一旦找到值,会立即返回。

package mainimport "github.com/tidwall/gjson"const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`func main() {value := gjson.Get(json, "name.last")println(value.String())
}

键路径

键路径实际上是以.分隔的一系列键。gjson支持在键中包含通配符*和?,*匹配任意多个字符,?匹配单个字符,例如ca*可以匹配cat、cate、cake等以ca开头的键,ca?只能匹配cat、cap等以ca开头且后面只有一个字符的键。

数组使用键名 + . + 索引(索引从 0 开始)的方式读取元素,如果键pets对应的值是一个数组,那么pets.0读取数组的第一个元素,pets.1读取第二个元素。

数组长度使用键名 + . + #获取,例如pets.#返回数组pets的长度。

如果键名中出现.,那么需要使用\进行转义。

路径语法

以下是对路径语法的快速概述,更多信息请参阅 GJSON 语法。

路径是通过点号分隔的一系列键。键可能包含特殊通配符 '*' 和 '?'。用索引作为键访问数组值。使用 '#' 字符获取数组元素的数量或访问子路径。点号和通配符可以用 '\' 转义。

{"name": {"first": "Tom", "last": "Anderson"},"age":37,"children": ["Sara","Alex","Jack"],"fav.movie": "Deer Hunter","friends": [{"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},{"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},{"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]}]
}

取值示例: 

"name.last"          >> "Anderson"
"age"                >> 37
"children"           >> ["Sara","Alex","Jack"]
"children.#"         >> 3
"children.1"         >> "Alex"
"child*.2"           >> "Jack"
"c?ildren.0"         >> "Sara"
"fav\.movie"         >> "Deer Hunter"
"friends.#.first"    >> ["Dale","Roger","Jane"]
"friends.1.last"     >> "Craig"

结果类型

GJSON 支持 JSON 类型 stringnumberbool 和 null。数组和对象以它们的原始 JSON 类型返回。

Result 类型持有这些之一:

bool, 对应 JSON 布尔值
float64, 对应 JSON 数字
string, 对应 JSON 字符串字面量
nil, 对应 JSON null

获取对象数组中的元素

var nitem types.NewItemvar responseData []types.NewItemlist_ := gjson.GetBytes(body, "subjects").Array()for _, item := range list_ {nitem.Id = item.Get("id").String()nitem.Title = item.Get("title").String()nitem.Cover = l.svcCtx.Config.MvConf.Referer + item.Get("images.small").String()nitem.Rate = item.Get("rating.average").Float()nitem.Pubdate = item.Get("pubdates.0").String()responseData = append(responseData, nitem)}

使用示例

解析豆瓣影视接口返回的数据:

func (l *NewMovieLogic) NewMovie(req *types.NewMovieReq) (resp *types.NewMovieResp, err error) {type Request struct {Req    types.NewMovieReqApiKey string `json:"apikey"`}req_ := Request{Req:    *req,ApiKey: l.svcCtx.Config.MvConf.ApiKey,}l.Debug(req_)url := l.svcCtx.Config.MvConf.BaseUrl + "/movie/new_movies"res, err_ := httpc.Do(l.ctx, http.MethodPost, url, req_)if err_ != nil {l.Error(err_)return nil, err_}defer res.Body.Close()body, err := io.ReadAll(res.Body)if err != nil {l.Errorf("Failed to read response body:", err)return nil, err}//格式化输出json//var str bytes.Buffer//_ = json.Indent(&str, []byte(body), "", "    ")//l.Debugf("formated: ", str.String())//l.Debug(keyValue)var nitem types.NewItemvar responseData []types.NewItemlist_ := gjson.GetBytes(body, "subjects").Array()for _, item := range list_ {nitem.Id = item.Get("id").String()nitem.Title = item.Get("title").String()nitem.Cover = l.svcCtx.Config.MvConf.Referer + item.Get("images.small").String()nitem.Rate = item.Get("rating.average").Float()nitem.Pubdate = item.Get("pubdates.0").String()responseData = append(responseData, nitem)}//t := reflect.TypeOf(keyVal["count"])//l.Debugf("Type: %v\n", t)if len(list_) != 0 {resp = &types.NewMovieResp{Code:    0,Message: res.Status,Data:    responseData,Count:   len(list_),Start:   0,Total:   len(list_),Title:   gjson.GetBytes(body, "title").String(),}} else {resp = &types.NewMovieResp{Code:    0,Message: res.Status,Data:    responseData,Count:   0,Start:   0,Total:   0,Title:   "",}}return resp, nil
}

其他资源

Go 语言 gjson对Json数据进行操作_go gjson-CSDN博客

34.Go操作JSON利器之gjson包_golang gjson-CSDN博客

GitCode - 全球开发者的开源社区,开源代码托管平台

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/852163.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Navigation的基本使用及其原理

Navigation的基本使用 1. 添加依赖 首先,在项目的build.gradle中添加Navigation组件库的依赖。 dependencies { implementation androidx.navigation:navigation-fragment:X.X.X implementation androidx.navigation:navigation-ui:X.X.X // 请替换X.X.X为当前最…

Go语言的GoFly快速开发框架已经支持Postgresql和Mysql两种数据库

两个数据库的选择 我们框架为了方便大家开发能更加业务场景选择不同侧重性能要求的数据,我们把MySQL和PostgreSQL两个在开源界很有名气数据库都支持进去。这样一个企业可以在开发习惯不改变情况下可以有两个选择。 这样的话我们在选择数据库系统时,需要…

Rust : windows下protobuf和压缩传输方案

此前dbpystream库是用python开发 web api。今天在rust中试用一下protobuf。 本文关键词:编译器、protobuf、proto文件、序列化、zstd压缩,build。 一、 protobuf编译器下载 具体见相关文章。没有编译器,protobuf无法运行。 windows参见&am…

【皇帝的新衣】虚拟小组长的团队管理

团队有时候会需要设立虚拟小组长来分组帮忙管理,那么,虚拟小组的负责人应当怎么做好管理动作? 目前很多大厂追求团队管理上的扁平化,但真正有实职的领导们一般管理30人数,此时需要一个虚拟小组长来分组帮忙管理。 一、…

字节出品SDXL-Lightning:文生图开放模型新突破

生成模型的研究中,文本到图像的生成一直是一个充满挑战的任务。传统的扩散模型虽然在生成质量上取得了显著的成果,但其生成过程往往需要大量的迭代步骤,这不仅导致计算成本高昂,而且生成速度缓慢,难以满足实时或近实时…

时间类:SimpleDateFormatk

一.作用 1.格式化:把时间变成我们喜欢的格式。 2.解析:把字符串表示的时间变成Date对象。 二.默认格式 SimpleDateFormat sdf1 new SimpleDateFormat();Date d1 new Date(0L); // format表示格式化的意思String str1 sdf1.format(d1);System.out.printl…

【MATLAB源码-第225期】基于matlab的计算器GUI设计仿真,能够实现基础运算,三角函数以及幂运算。

操作环境: MATLAB 2022a 1、算法描述 界面布局 计算器界面的主要元素分为几大部分:显示屏、功能按钮、数字按钮和操作符按钮。 显示屏 显示屏(Edit Text):位于界面顶部中央,用于显示用户输入的表达式和…

没有特斯拉的开源专利,就没有中国电动车产业今天的成就?

原文链接:没有特斯拉的开源专利,就没有中国电动车产业今天的成就? 特斯拉的开源专利,对中国电动车产业的影响有多大? 2014年6月12日(June 12, 2014),特斯拉(TESLA&…

nodejs 某音douyin网页端搜索接口及x_bogus、a_bogus(包含完整源码)(2024-06-13)

前言 x_bogus或a_bogus算法大概是对数据、ua、时间戳、浏览器的几个指纹进行计算,拿到一个110位大数组,然后转字符,在头部再添加十二位随机字符,再进行魔改的base64加密。 问:抖音的x_bogus、a_bogus值有什么用&#x…

react路由的使用

安装 npm install react-router-dom main.tsx中配置 import React from react import { RouterProvider } from react-router-dom import ReactDOM from react-dom/client import App from ./App.tsx import normalize.css import ./index.cssimport router from ./router/i…

网工内推 | 外企、上市公司运维工程师,有软考中高项证书优先

01 优尼派特(苏州)物流有限公司 🔷招聘岗位:软件运维测试工程师 🔷任职要求: 1、负责公司自主研发的软件售后服务工作, 包括软件的安装, 调试, 升级,培训, 参数配置, 需求与Bug的处理; 2、负责数据库升级及…

远程主机强迫关闭了一个现有的连接redis

引言 在使用 Redis 进行开发和运维过程中,我们可能会遇到 Redis 连接被远程主机强制关闭的情况。本文将介绍造成这种情况的原因,并给出一些处理方法和建议。 远程主机强制关闭连接的原因 远程主机强制关闭连接通常是由于网络不稳定、连接超时、Redis 配…

数据质量测试:测试数据有效性和准确性的方法

以下为作者观点,来看看你认同吗? 如果西西弗斯(编者注:希腊神话中的人物)是一个数据分析师或数据科学家,他在山上滚动的巨石将是他的数据质量保障。即使所有获取、处理和建模的工程流程都无懈可击&#xf…

HarmonyOs修改应用名称和图标方法

最近在开发Harmony应用,发现修改app.json5下的lable:app_name和icon不生效 后来经过查找,原来还需要更改entry下的src/main/module.json5才行,具体操作路径是: 更改后生效:

一步一步用numpy实现神经网络各种层

1. 首先准备一下数据 if __name__ "__main__":data np.array([[2, 1, 0],[2, 2, 0],[5, 4, 1],[4, 5, 1],[2, 3, 0],[3, 2, 0],[6, 5, 1],[4, 1, 0],[6, 3, 1],[7, 4, 1]])x data[:, :-1]y data[:, -1]for epoch in range(1000):...2. 实现SoftmaxCrossEntropy层…

Vue31-自定义指令:总结

一、自定义函数的陷阱 1-1、自定义函数名 自定义函数名,不能用驼峰式!!! 示例1: 示例2: 1-2、指令回调函数的this 【回顾】: 所有由vue管理的函数,里面的this直接就是vm实例对象。…

Linux发邮件的工具推荐有哪些?如何配置?

Linux发邮件的功能怎么样?Linux系统如何设置服务器? 在Linux操作系统中,有多种工具可供选择用来发送电子邮件,每种工具都有其独特的特点和适用场景。AokSend将介绍几种常用的Linux发邮件工具,并分析它们的优缺点和适用…

Linux Kernel入门到精通系列讲解(QEMU-虚拟化篇) 2.5 Qemu实现RTC设备

1. 概述 上一章节起(5.4小节),我们已经把整个Naruto Pi都跑通了,从BL0到kernel再到Rootfs都通了,目前可以说已经具备学习Linux得基础条件,剩下得都只是添砖加瓦,本小节我们将添加RTC,如果你还没有添加RTC,你可以试试不添加RTC时,Linux的时间戳会很奇怪,加了RTC后,…

Linux部署mysql8.0.28数据库

目录 1.基础准备 (1)首先去官网下载二进制安装包 (2)下载好之后上传至服务器 (3)禁用关闭selinux和防火墙 (4)挂载光盘搭建本地yum仓库 2.解压到指定目录 3.检查系统是否安装mariadb 4.安装MySQL数据库 (1)进入MySQL目录 看到‘完毕’就说面mysql已经安装成功了 4.初…

Python数据结构——集合(详细版)

集合是一种可迭代的、无序的、不能包含重复元素的数据结构。与序列相比,序列中的元素是有序的,可以重复出现,而集合中的元素是无序且不能有重复元素。 序列强调的是有序,集合强调的是不重复。当不考虑顺序,且没有重复…