当前位置: 首页 > news >正文

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.lryc.cn/news/376039.html

相关文章:

  • 基于Langchain构建本地大型语言模型(LLM)问答系统的经验分享
  • 对抗式生成模仿学习(GAIL)
  • 信息系统项目管理师 | 新一代信息技术
  • 安全宣传咨询日活动向媒体投稿记住这个投稿好方法
  • 第7章:系统架构设计基础知识-软件架构风格
  • 自制调色小工具给图片加滤镜,修改图片红、绿、蓝通道及亮度,修改图片颜色
  • 【Redis】java客户端(SpringData和jedis)
  • 大数据安全经典面试题及回答(上)
  • vi/vim使用命令
  • webpack打包gz文件,nginx开启gzip压缩
  • 微服务开发与实战Day11 - 微服务面试篇
  • 基于Spring Boot+VUE职称评审管理系统
  • MySQL 基本语法讲解及示例(上)
  • 6.18作业
  • Excel文件转换为HTML文件
  • MySQL数据库入门
  • vue element-ui 下拉框 以及 input 限制输入,小数点后保留两位 界面设计案例 和 例子:支持mp4和m3u8视频播放
  • Python基础用法 之 运算符
  • 事务所管理系统的设计
  • airsim安装
  • 打造精致UI界面:字体设计的妙招
  • [BJDCTF2020]ZJCTF,不过如此1
  • 全网最全 Kimi 使用手册,看完 Kimi 效率提升 80%
  • “Redis中的持久化:深入理解RDB与AOF机制“
  • PHP框架详解:Symfony框架讲解
  • PR软件视频抠图换背景
  • 下载依赖有问题(只有自己有问题)
  • vscode-关闭ts与js语义校验
  • 风控中的文本相似方法之余弦定理
  • Spring Boot定时任务编程指南:如何创建和配置周期性任务