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

时间:2025-03-08 08:20:13

目录

简介

安装

原生的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 类型 stringnumberbool 和 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 - 全球开发者的开源社区,开源代码托管平台