目录
简介
安装
原生的json解析
Gjson使用举例
基本使用
键路径
使用示例
其他资源
简介
在 Golang 中,解析 JSON 数据是一项非常常见的任务。Go提供了标准的JSON包,可以轻松地将JSON数据序列化和反序列化。但是,在使用标准JSON包解析大型复杂JSON结构时,可能存在些许不足,例如代码冗余,性能瓶颈等问题。针对这些问题,目前有许多优秀的JSON解析框架,GJSON是其中一个很不错的选择。
GJSON 是一个 Go 包,提供了一种 高效 和 简单 的方式来从 JSON 文档中提取值。它具有如 一行检索、点号路径语法、迭代 和 解析 JSON 行 等特性。
本文将详细讲解如何使用GJSON框架解析JSON数据。
安装
GJSON模块可以通过go get命令来安装。
go get -u /tidwall/gjson
原生的json解析
以解析豆瓣接口/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": "\/view\/celebrity\/m\/public\/p1371934661.",
"large": "\/view\/celebrity\/m\/public\/p1371934661.",
"medium": "\/view\/celebrity\/m\/public\/p1371934661."
},
"name_en": "Henry Cavill",
"name": "\u4ea8\u5229\u00b7\u5361\u7ef4\u5c14",
"alt": "https:\/\/\/celebrity\/1044713\/",
"id": "1044713"
},
{
"avatars": {
"small": "\/view\/celebrity\/m\/public\/p1607496406.",
"large": "\/view\/celebrity\/m\/public\/p1607496406.",
"medium": "\/view\/celebrity\/m\/public\/p1607496406."
},
"name_en": "Eiza Gonz\u00e1lez",
"name": "\u827e\u838e\u00b7\u5188\u8428\u96f7\u65af",
"alt": "https:\/\/\/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": "\/view\/celebrity\/m\/public\/",
"large": "\/view\/celebrity\/m\/public\/",
"medium": "\/view\/celebrity\/m\/public\/"
},
"name_en": "Guy Ritchie",
"name": "\u76d6\u00b7\u91cc\u5947",
"alt": "https:\/\/\/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": "\/view\/photo\/s_ratio_poster\/public\/",
"large": "\/view\/photo\/s_ratio_poster\/public\/",
"medium": "\/view\/photo\/s_ratio_poster\/public\/"
},
"alt": "https:\/\/\/subject\/34971728\/",
"id": "34971728"
}
],
"title": "\u8c46\u74e3\u7535\u5f71\u65b0\u7247\u699c"
}
使用golang原始的方式,将响应体JSON反序列化为一个字典(map),以便于访问其中的数据。
body, err := ()
if err != nil {
("Failed to read response body:", err)
return nil, err
}
//格式化输出json
//var str
//_ = (&str, []byte(body), "", " ")
//("formated: ", ())
var keyVal map[string]interface{}
err = (body, &keyVal)
if err != nil {
("Failed to extract key value:", err)
}
//(keyValue)
var hot
var responseData []
list_, ok := keyVal["subjects"].([]interface{})
if ok {
for _, item := range list_ {
itemMap, ok := item.(map[string]interface{})
if ok {
//(itemMap)
= itemMap["id"].(string)
= itemMap["title"].(string)
tmp := itemMap["images"].(map[string]interface{})
= + tmp["small"].(string)
= itemMap["rating"].(map[string]interface{})["average"].(float64)
}
responseData = append(responseData, hot)
}
}
示例如下:
func (l *HotMovieLogic) HotMovie(req *) (resp *, err error) {
// todo: add your logic here and delete this line
type Request struct {
Req
ApiKey string `json:"apikey"`
}
req_ := Request{
Req: *req,
ApiKey: ,
}
(req_)
url := + "/movie/in_theaters"
res, err_ := (, , url, req_)
if err_ != nil {
(err_)
return nil, err_
}
defer ()
body, err := ()
if err != nil {
("Failed to read response body:", err)
return nil, err
}
//格式化输出json
//var str
//_ = (&str, []byte(body), "", " ")
//("formated: ", ())
var keyVal map[string]interface{}
err = (body, &keyVal)
if err != nil {
("Failed to extract key value:", err)
}
//(keyValue)
var hot
var responseData []
list_, ok := keyVal["subjects"].([]interface{})
if ok {
for _, item := range list_ {
itemMap, ok := item.(map[string]interface{})
if ok {
//(itemMap)
= itemMap["id"].(string)
= itemMap["title"].(string)
tmp := itemMap["images"].(map[string]interface{})
= + tmp["small"].(string)
= itemMap["rating"].(map[string]interface{})["average"].(float64)
}
responseData = append(responseData, hot)
}
}
//t := (keyVal["count"])
//("Type: %v\n", t)
resp = &{
Code: 0,
Message: ,
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 main
import (
"fmt"
"/tidwall/gjson"
)
func main() {
json := `{"name":{"first":"li","last":"dj"},"age":18}`
lastName := (json, "")
("last name:", ())
age := (json, "age")
("age:", ())
email := (json, "email")
// json 中不存在该字段时,String为空串,Int为0,即返回想要转换的类型的零值
("email:", ())
}
使用很简单,只需要传入 JSON
串和要读取的键路径即可。注意一点细节,因为()
函数实际上返回的是类型,我们要调用其相应的方法进行转换对应的类型。如上面的
String()
和Int()
方法。
获取值
Get
函数搜索 JSON 中指定的路径。路径以点号分隔,如 "" 或 "age"。一旦找到值,会立即返回。
package main
import "/tidwall/gjson"
const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}`
func main() {
value := (json, "")
println(())
}
键路径
键路径实际上是以.分隔的一系列键。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"],
"": "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"]}
]
}
取值示例:
"" >> "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." >> "Craig"
结果类型
GJSON 支持 JSON 类型 string
, number
, bool
和 null
。数组和对象以它们的原始 JSON 类型返回。
Result
类型持有这些之一:
bool, 对应 JSON 布尔值
float64, 对应 JSON 数字
string, 对应 JSON 字符串字面量
nil, 对应 JSON null
获取对象数组中的元素
var nitem
var responseData []
list_ := (body, "subjects").Array()
for _, item := range list_ {
= ("id").String()
= ("title").String()
= + ("").String()
= ("").Float()
= ("pubdates.0").String()
responseData = append(responseData, nitem)
}
使用示例
解析豆瓣影视接口返回的数据:
func (l *NewMovieLogic) NewMovie(req *) (resp *, err error) {
type Request struct {
Req
ApiKey string `json:"apikey"`
}
req_ := Request{
Req: *req,
ApiKey: ,
}
(req_)
url := + "/movie/new_movies"
res, err_ := (, , url, req_)
if err_ != nil {
(err_)
return nil, err_
}
defer ()
body, err := ()
if err != nil {
("Failed to read response body:", err)
return nil, err
}
//格式化输出json
//var str
//_ = (&str, []byte(body), "", " ")
//("formated: ", ())
//(keyValue)
var nitem
var responseData []
list_ := (body, "subjects").Array()
for _, item := range list_ {
= ("id").String()
= ("title").String()
= + ("").String()
= ("").Float()
= ("pubdates.0").String()
responseData = append(responseData, nitem)
}
//t := (keyVal["count"])
//("Type: %v\n", t)
if len(list_) != 0 {
resp = &{
Code: 0,
Message: ,
Data: responseData,
Count: len(list_),
Start: 0,
Total: len(list_),
Title: (body, "title").String(),
}
} else {
resp = &{
Code: 0,
Message: ,
Data: responseData,
Count: 0,
Start: 0,
Total: 0,
Title: "",
}
}
return resp, nil
}
其他资源
Go 语言 gjson对Json数据进行操作_go gjson-****博客
操作JSON利器之gjson包_golang gjson-****博客
GitCode - 全球开发者的开源社区,开源代码托管平台