内容简介: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的键。
我们如何找到相应的字段?
- 首先,Go尝试查找标签包含Foo的(大写)导出字段。
- 如果找不到匹配项,请查找名称为Foo的字段。
- 如果仍然没有匹配,请查找类似FOO或FoO的内容,忽略区分大小写。
您可能已经注意到,应该导出要分配的所有字段,并且Go仅分配可以找到的字段,而忽略所有其他字段。
如果您需要处理大块的JSON数据,但只有它的一个特定子集,这可能很有用。
您不需要的数据很容易被丢弃。
解析为接口
当我们事先知道期望什么样的JSON时,我们可以将它解析为特定的结构。
但是,如果我们不知道怎么办?
我们知道interface{}可以是Go中的任何内容,因此它是保存未知格式的JSON的最佳容器。
JSON包使用map[string]interface{}和[]interface{}来保存各种JSON对象和数组。
以下是JSON映射关系列表:
- bool代表JSON布尔值,
- float64代表JSON数字,
- string表示JSON字符串,
- 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()
生成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时,您需要记住以下几点:
- 不输出包含“ - ”的字段标签。
- 如果标记包含自定义名称,则Go使用此名称而不是字段名称,如上例中的serverName。
- 如果标签包含omitempty,则如果该字段为零值,则不会输出该字段。
- 如果字段类型是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函数只有在成功时返回数据,所以这里有一些我们需要记住的要点:
- JSON仅支持字符串作为键,因此如果要对映射进行编码,则其类型必须为map[string]T,其中T是Go中的类型。
- 通道,复杂类型和函数等类型无法编码为JSON。
- 不要尝试编码循环数据,它会导致无限递归。
- 如果该字段是指针,则Go输出它指向的数据,否则如果指向nil则输出null。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Java生成、解析二维码
- Python生成器以及应用实例解析
- Django源码解析|Migrations文件的生成
- golang生成JSON及解析JSON
- Python 迭代器、生成器和列表解析
- Go基础学习记录之如何解析并生成XML
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。