Go基础学习记录之如何解析并生成JSON

栏目: Go · 发布时间: 6年前

内容简介:JSON(JavaScript Object Notation)是一种基于文本描述的轻量级数据交换语言。它的优点包括自我描述,易于理解等。即使它是JavaScript的一个子集,JSON使用不同的文本格式,结果是它可以被视为一种独立的语言。JSON与C系列语言具有相似性。

JSON

JSON(JavaScript Object Notation)是一种基于文本描述的轻量级数据交换语言。

它的优点包括自我描述,易于理解等。即使它是JavaScript的一个子集,JSON使用不同的文本格式,结果是它可以被视为一种独立的语言。

JSON与C系列语言具有相似性。

JSON和XML之间最大的区别在于XML是一种完整的标记语言,而JSON则不是。

JSON比XML更小更快,因此在浏览器中解析更加容易和快捷,这也是许多开放平台选择使用JSON作为数据交换接口语言的原因之一。

由于JSON在Web开发中变得越来越重要,让我们来看看 Go 对JSON的支持程度。

你会发现Go的标准库对编码和解码JSON有很好的支持。

{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}

后面的部分将使用此JSON数据在Go中引入JSON概念。

解析JSON

解析为Struct

假设我们在上面的例子中有JSON。

我们如何解析这些数据并将其映射到Go中的结构?Go为此提供了以下功能:

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

我们可以像这样使用这个函数:

package controllers

import (
    "encoding/json"
    "fmt"
    "net/http"
)

type JsonServer struct {
    ServerName string
    StringIP   string
}

type JsonServers struct {
    Servers []JsonServer
}

func Json(w http.ResponseWriter, r *http.Request) {
    var s JsonServers
    str := `{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}`
    json.Unmarshal([]byte(str), &s)
    fmt.Println(str)
}

运行后得到如下结果

{[{Shanghai_VPN 127.0.0.1} {Beijing_VPN 127.0.0.2}]}

在上面的示例中,我们在Go中为JSON定义了相应的结构,使用slice作为JSON对象数组,使用字段名作为JSON键。

但Go如何知道哪个JSON对象对应于哪个特定结构域?

假设我们在JSON中有一个名为Foo的键。

我们如何找到相应的字段?

  1. 首先,Go尝试查找标签包含Foo的(大写)导出字段。
  2. 如果找不到匹配项,请查找名称为Foo的字段。
  3. 如果仍然没有匹配,请查找类似FOO或FoO的内容,忽略区分大小写。

您可能已经注意到,应该导出要分配的所有字段,并且Go仅分配可以找到的字段,而忽略所有其他字段。

如果您需要处理大块的JSON数据,但只有它的一个特定子集,这可能很有用。

您不需要的数据很容易被丢弃。

解析为接口

当我们事先知道期望什么样的JSON时,我们可以将它解析为特定的结构。

但是,如果我们不知道怎么办?

我们知道interface{}可以是Go中的任何内容,因此它是保存未知格式的JSON的最佳容器。

JSON包使用map[string]interface{}和[]interface{}来保存各种JSON对象和数组。

以下是JSON映射关系列表:

  1. bool代表JSON布尔值,
  2. float64代表JSON数字,
  3. string表示JSON字符串,
  4. nil表示JSON null。

假设我们有以下JSON数据:

b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)

现在我们将这个JSON解析为interface{}:

var f interface{}
err := json.Unmarshal(b, &f)

f存储一个映射,其中键是字符串,值是interface{}'s'。

f = map[string]interface{}{
    "Name": "Wednesday",
    "Age":  6,
    "Parents": []interface{}{
        "Gomez",
        "Morticia",
    },
}

那么,我们如何访问这些数据?键入断言。

m := f.(map[string]interface{})

断言后,您可以使用以下代码访问数据:

for k, v := range m {
    switch vv := v.(type) {
    case string:
        fmt.Println(k, "is string", vv)
    case int:
        fmt.Println(k, "is int", vv)
    case float64:
        fmt.Println(k,"is float64",vv)
    case []interface{}:
        fmt.Println(k, "is an array:")
        for i, u := range vv {
            fmt.Println(i, u)
        }
    default:
        fmt.Println(k, "is of a type I don't know how to handle")
    }
}

如您所见,我们现在可以通过interface{}解析未知格式的JSON并键入断言。

以上示例是官方解决方案,但类型断言并不总是方便。

因此,我推荐一个名为simplejson的开源项目,由bitly创建和维护。

以下是如何使用此项目处理未知格式的JSON的示例:

js, err := NewJson([]byte(`{
    "test": {
        "array": [1, "2", 3],
        "int": 10,
        "float": 5.150,
        "bignum": 9223372036854775807,
        "string": "simplejson",
        "bool": true
    }
}`))

arr, _ := js.Get("test").Get("array").Array()
i, _ := js.Get("test").Get("int").Int()
ms := js.Get("test").Get("string").MustString()

不难看出这是多么方便。

查看存储库以查看更多信息:

https://github.com/bitly/go-s...

生成JSON

在许多情况下,我们需要生成JSON数据并响应客户端。

在Go中,JSON包有一个名为Marshal的函数来执行以下操作:

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

假设我们需要生成服务器信息列表。

我们有以下样本:

package controllers

import (
    "encoding/json"
    "fmt"
    "net/http"
)

type JsonServer struct {
    ServerName string
    ServerIP   string
}

type JsonServers struct {
    Servers []JsonServer
}

func JsonProcess(w http.ResponseWriter, r *http.Request) {
    var s JsonServers
    s.Servers = append(s.Servers, JsonServer{
        ServerName: "Shanghai_VPN",
        ServerIP:   "127.0.0.1",
    })

    s.Servers = append(s.Servers, JsonServer{
        ServerName: "Beijing_VPN",
        ServerIP:   "127.0.0.2",
    })

    b, err := json.Marshal(s)

    if err != nil {
        fmt.Println("json err:", err)
        return
    }

    fmt.Println(string(b))
}

输出结果如下:

{"Servers":[{"ServerName":"Shanghai_VPN","ServerIP":"127.0.0.1"},{"ServerName":"Beijing_VPN","ServerIP":"127.0.0.2"}]}

如您所知,所有字段名称都是大写的,但如果您希望JSON键名以小写字母开头,则应使用struct标签。

否则,Go将不会为内部字段生成数据。

type JsonServer struct {
    ServerName string `json:"serverName"`
    ServerIP   string `json:"serverIP"`
}

type JsonServers struct {
    Servers []JsonServer `json:"servers"`
}

在此修改之后,我们可以生成与以前相同的JSON数据。

在尝试生成JSON时,您需要记住以下几点:

  1. 不输出包含“ - ”的字段标签。
  2. 如果标记包含自定义名称,则Go使用此名称而不是字段名称,如上例中的serverName。
  3. 如果标签包含omitempty,则如果该字段为零值,则不会输出该字段。
  4. 如果字段类型是bool,string,int,int64等,并且其标记包含",string",则Go会将此字段转换为其对应的JSON类型。

示例如下

type TestJsonServer struct {
    // ID不会被输出
    ID int `json:"-"`

    // ServerName2 不会转换为JSON类型
    ServerName  string `json:"serverName"`
    ServerName2 string `json:"serverName2,string"`

    // 如果ServerIP是空的将不会被输出
    ServerIP string `json:"serverIP,omitempty"`
}


func JsonToTest(w http.ResponseWriter, r *http.Request) {
    s := TestJsonServer{
        ID:          3,
        ServerName:  `Go "1.0" `,
        ServerName2: `Go "1.0" `,
        ServerIP:    ``,
    }

    b, _ := json.Marshal(s)
    os.Stdout.Write(b)
}

输出如下

{"serverName":"Go \"1.0\" ","serverName2":"\"Go \\\"1.0\\\" \""}

Marshal函数只有在成功时返回数据,所以这里有一些我们需要记住的要点:

  1. JSON仅支持字符串作为键,因此如果要对映射进行编码,则其类型必须为map[string]T,其中T是Go中的类型。
  2. 通道,复杂类型和函数等类型无法编码为JSON。
  3. 不要尝试编码循环数据,它会导致无限递归。
  4. 如果该字段是指针,则Go输出它指向的数据,否则如果指向nil则输出null。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数字乌托邦

数字乌托邦

尼古拉斯•卡尔 / 姜忠伟 / 中信前沿出版社 / 2018-5 / 69.00

当下,技术与我们的关系变得越来越紧密不可分割,特别是智能手机等设备的出现,带给整个人类社会一场彻底的变革。的确,智能手机上的各种应用程序让我们的工作生活无比便利:社交媒体让我们能够和他人实时保持联络并传输信息,不再受时间、地点的限制;搜索引擎通过精准的算法将我们所需要的信息整合推送至屏幕上,让我们毫不费力就看到自己想要的;地图软件为我们的出行提供了更多路线选择,甚至可以使用语音导航,帮助我们顺利到......一起来看看 《数字乌托邦》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换