使用Go语言解析动态JSON格式的方法

 更新时间:2017年12月18日 09:22:02   作者:HP''''S Memory  
本篇文章主要介绍了使用Go语言解析动态JSON格式的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

通常使用Golang encoding/json 标准库可以方便的编码/解析JSON数据,但是前提需要定义struct数据结构。特别是解析未知结构的JSON数据时,原有方法很难满足需求了,本文主要介绍动态解析JSON格式。

Go语言的JSON 库

Go语言自带的JSON转换库为 encoding/json

1.1)其中把对象转换为JSON的方法(函数)为 json.Marshal(),其函数原型如下

func Marshal(v  interface{}) ([]byte, error)

也就是说,这个函数接收任意类型的数据 v,并转换为字节数组类型,返回值就是我们想要的JSON数据和一个错误代码。当转换成功的时候,这个错误代码为nil

在进行对象转换为 JSON 的过程中,会遵循如下几条规则:

  1. 布尔型转换为 JSON 后仍是布尔型 , 如true -> true
  2. 浮点型和整数型转换后为JSON里面的常规数字,如 1.23 -> 1.23
  3. 字符串将以UTF-8编码转化输出为Unicode字符集的字符串,特殊字符比如<将会被转义为\u003c
  4. 数组和切片被转换为JSON 里面的数组,[]byte类会被转换为base64编码后的字符串,slice的零值被转换为null
  5. 结构体会转化为JSON对象,并且只有结构体里边以大写字母开头的可被导出的字段才会被转化输出,而这些可导出的字段会作为JSON对象的字符串索引
  6. 转化一个map 类型的数据结构时,该数据的类型必须是 map[string]T(T 可以是encoding/json 包支持的任意数据类型)

1.2)把 JSON 转换回对象的方法(函数)为 json.Unmarshal(),其函数原型如下

func Unmarshal(data [] byte, v interface{}) error

这个函数会把传入的 data 作为一个JSON来进行解析,解析后的数据存储在参数 v 中。这个参数 v 也是任意类型的参数(但一定是一个类型的指针),原因是我们在是以此函数进行JSON 解析的时候,这个函数不知道这个传入参数的具体类型,所以它需要接收所有的类型。

那么,在进行解析的时候,如果JSON 和 对象的结构不对口会发生什么呢,这就需要解析函数json.Unmarshal()遵循以下规则

json.Unmarshal() 函数会根据一个约定的顺序查找目标结构中的字段,如果找到一个即发生匹配。那什么是找到了呢?关于“找到了”又有如下的规则:假设一个JSON对象有个名为"Foo"的索引,要将"Foo"所对应的值填充到目标结构体的目标字段上,json.Unmarshal() 将会遵循如下顺序进行查找匹配

  1. § 一个包含Foo 标签的字段
  2. §  一个名为Foo 的字段
  3. § 一个名为Foo 或者Foo 或者除了首字母其他字母不区分大小写的名为Foo 的字段。 这些字段在类型声明中必须都是以大写字母开头、可被导出的字段。

注意:如果JSON中的字段在Go目标类型中不存在,json.Unmarshal() 函数在解码过程中会丢弃该字段。

当JSON 的结构是未知的时候,会遵循如下规则:

  1. § JSON中的布尔值将会转换为Go中的bool类型
  2. § 数值会被转换为Go中的float64类型
  3. § 字符串转换后还是string类型
  4. § JSON数组会转换为[]interface{} 类型
  5. § JSON对象会转换为map[string]interface{}类型
  6. § null值会转换为nil

注意:在Go的标准库encoding/json包中,允许使用map[string]interface{}和[]interface{} 类型的值来分别存放未知结构的JSON对象或数组

1、传统方法

比如 User 数据结构如下:

type User struct {
 Name string `json:"name"`
 Age int  `json:"age"`
}

在定义struct字段的时候,可以在字段后面添加tag,来控制encode/decode的过程:是否要 decode/encode 某个字段,JSON 中的字段名称是什么。字段名首字母控制字段的可见性,若要输出到JSON,首字母需要大写。

三种tag:

- :不要解析这个字段

omitempty :当字段为空(默认值)时,不要解析这个字段。比如 false、0、nil、长度为 0 的 array,map,slice,string

FieldName :当解析 json 的时候,使用这个名字

举例来说吧:

// 解析的时候忽略该字段。默认情况下会解析这个字段,因为它是大写字母开头的
Field int `json:"-"`
// 解析(encode/decode) 的时候,使用 `other_name`,而不是 `Field`
Field int `json:"other_name"`
// 解析的时候使用 `other_name`,如果struct 中这个值为空,就忽略它
Field int `json:"other_name,omitempty"`

(1)encode

user := User{Name: "test", Age:23}
data, err := json.Marshal(user)
if err != nil {
 fmt.Println(string(data))
}

data 就是 []byte 类型的数组,里面包含了解析为 JSON 之后的数据,可以使用string(data)转型为string。

(2)decode

要把JSON数据转换成Go类型的值(Decode),可以使用 json.Unmarshal 。

var user User
err = json.Unmarshal(data, &user)
if err != nil {
 fmt.Errorf("Can not decode data: %v\n", err)
}

2、动态解析

动态JSON结构未知,若使用前面方法需要事先定义数据结构,这与PHP/Python JSON处理非常不同。若不考虑性能,使用simplejson。

(1)simplejson

js, err := simplejson.NewJson([]byte(`{
 "test": {
  "string_array": ["asdf", "zxcv"],
  "array": [1, "2", 3],
  "arraywithsubs": [{"subkeyone": 1},
  "bignum": 9223372036854775807,
  "string": "simplejson",
  "bool": true
 }
 }`))
 if err != nil {
  panic("json format error")
 }
 //获取某个字段值
 s, err := js.Get("test").Get("string").String()
 if err != nil {
  panic(err)
 }
 fmt.Println(s)
 //检查某个字段是否存在
 _, ok := js.Get("test").CheckGet("string2")
 if ok {
  fmt.Println("存在!")
 } else {
  fmt.Println("不存在")
 }

(2)interface

比如JSON有以下两种类型:

{"Type":"sound","Msg":{"Description":"dynamite","Authority":"the Bruce Dickinson"}}
{"Type":"cowbell","Msg":{"More":true}}

Msg 具体什么类型实现无法判断, Msg being a map[string]interface{} :

type Envelope struct {
 Type string
 Msg interface{}
}

var env Envelope
if err := json.Unmarshal([]byte(input), &env); err != nil {
  log.Fatal(err)
 }
// for the love of Gopher DO NOT DO THIS
var desc string = env.Msg.(map[string]interface{})["description"].(string)
fmt.Println(desc)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 使用Go语言编写一个简单的Web框架

    使用Go语言编写一个简单的Web框架

    Go语言(又称Golang)因其高效的性能和简洁的语法,在编写Web框架方面表现出色,下面将详细介绍如何使用Go语言编写一个简单的Web框架,文中有详细的代码供大家参考,需要的朋友可以参考下
    2024-05-05
  • Golang WaitGroup 底层原理及源码解析

    Golang WaitGroup 底层原理及源码解析

    WaitGroup 是 Golang 中最常见的并发控制技术之一,它的作用我们可以简单类比为其他语言中多线程并发控制中的 join(),这篇文章主要介绍了Golang WaitGroup 底层原理及源码详解,需要的朋友可以参考下
    2023-04-04
  • golang中的单引号转义问题

    golang中的单引号转义问题

    这篇文章主要介绍了golang中的单引号转义问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • golang进行xml文件解析的操作方法

    golang进行xml文件解析的操作方法

    本文介绍了Go语言中解析XML文件的几种方法:小文件解析、大文件流式解析和复杂结构解析,对于小文件,使用标准库中的encoding/xml包;对于大文件,采用流式解析以避免内存溢出,对于复杂结构的XML文件,推荐使用第三方库github.com/beevik/etree
    2024-11-11
  • goFrame的gqueue与channe的区别

    goFrame的gqueue与channe的区别

    这篇文章主要介绍了goFrame的gqueue与channe的区别,channel的作用是用于go协程间的通信,goroutine和channel是支持高并发的重要组成部分,更多两者详细介绍需要的小伙伴可以参考下面文章内容
    2022-06-06
  • Go分布式链路追踪实战探索

    Go分布式链路追踪实战探索

    这篇文章主要为大家介绍了Go分布式链路追踪实战示例探索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • 详解golang中bufio包的实现原理

    详解golang中bufio包的实现原理

    这篇文章主要介绍了详解golang中bufio包的实现原理,通过分析golang中bufio包的源码,来了解为什么bufio能够提高文件读写的效率和速度
    2018-01-01
  • 一文带你搞懂Golang依赖注入的设计与实现

    一文带你搞懂Golang依赖注入的设计与实现

    在现代的 web 框架里面,基本都有实现了依赖注入的功能,可以让我们很方便地对应用的依赖进行管理。今天我们来看看 go 里面实现依赖注入的一种方式,感兴趣的可以了解一下
    2023-01-01
  • 快速掌握Go 语言 HTTP 标准库的实现方法

    快速掌握Go 语言 HTTP 标准库的实现方法

    基于HTTP构建的服务标准模型包括两个端,客户端(Client)和服务端(Server),这篇文章主要介绍了Go 语言HTTP标准库的实现方法,需要的朋友可以参考下
    2022-07-07
  • GO使用Mutex确保并发程序正确性详解

    GO使用Mutex确保并发程序正确性详解

    这篇文章主要为大家介绍了GO使用Mutex确保并发程序正确性详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03

最新评论