分析JSON的步骤和分析XML的步骤基本相同——分析程序首先要做的就是把JSON的分析结果存储到一些结构里面,然后通过访问这些结构来提取数据。下面是分析JSON的两个常见步骤(这个过程如图7-7所示):
图7-7 使用Go分析JSON:创建结构并将JSON解封到结构里面
- 创建一些用于包含JSON数据的结构;
- 通过
json.Unmarshal
函数,把JSON数据解封到结构里面。
跟映射XML相比,把结构映射至JSON要简单得多,后者只有一条通用的规则:对于名字为<name>
的JSON键,用户只需要在结构里创建一个任意名字的字段,并将该字段的结构标签设置为'json:"<name>"'
,就可以把JSON键<name>
的值存储到这个字段里面。接下来,就让我们来看一个实际的例子。
代码清单7-9展示了一个名为post.json
的JSON文件,我们接下来就要对这个文件进行分析。因为这个JSON文件包含的数据跟之前分析的XML文件包含的数据是相同的,所以这些数据对你来说应该不会感到陌生。
代码清单7-9 要分析的JSON文件
{
"id" : 1,
"content" : "Hello World!",
"author" : {
"id" : 2,
"name" : "Sau Sheong"
},
"comments" : [
{
"id" : 3,
"content" : "Have a great day!",
"author" : "Adam"
},
{
"id" : 4,
"content" : "How are you today?",
"author" : "Betty"
}
]
}
代码清单7-10展示了json.go
文件包含的代码,这些代码会分析post.json
文件,并将其包含的JSON数据解封至相应的结构。需要注意的是,除了结构标签之外,这个程序使用的结构跟之前分析XML时使用的结构并无不同。
代码清单7-10 JSON分析程序
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type Post struct {
Id int `json:"id"`// 定义一些结构,用于表示数据
Content string `json:"content"`
Author Author `json:"author"`
Comments []Comment `json:"comments"`
}
type Author struct {
Id int `json:"id"`
Name string `json:"name"`
}
type Comment struct {
Id int `json:"id"`
Content string `json:"content"`
Author string `json:"author"`
}
func main() {
jsonFile, err := os.Open("post.json")
if err != nil {
fmt.Println("Error opening JSON file:", err)
return
}
defer jsonFile.Close()
jsonData, err := ioutil.ReadAll(jsonFile)
if err != nil {
fmt.Println("Error reading JSON data:", err)
return
}
var post Post
json.Unmarshal(jsonData, &post)//将JSON数据解封至结构
fmt.Println(post)
}
为了将JSON键id
的值映射到Post
结构的Id
字段,程序将该字段的结构标签设置成了'json:"id"'
,这种设置基本上就是将结构映射至JSON数据所需完成的全部工作。跟分析XML时一样,分析程序通过切片来嵌套多个结构,从而使一篇帖子可以包含零个或多个评论。除此之外,JSON的解封操作也跟XML的解封操作一样,都可以通过调用Unmarshal
函数来完成。
我们可以通过执行以下命令来运行这个JSON分析程序:
go run json.go
如果一切正常,应该会看到以下结果:
{1 Hello World! {2 Sau Sheong} [{3 Have a great day! Adam}{4 How are you today? Betty}]}
跟分析XML时一样,用户除了可以使用Unmarshal
函数来解封JSON,还可以使用Decoder
手动地将JSON数据解码到结构里面,以此来处理流式的JSON数据,图7-8以及代码清单7-11展示了这个过程的具体实现。
图7-8 使用Go分析JSON:将JSON解码至结构
代码清单7-11 使用Decoder对JSON进行语言分析
jsonFile, err := os.Open("post.json")
if err != nil {
fmt.Println("Error opening JSON file:", err)
return
}
defer jsonFile.Close()
decoder := json.NewDecoder(jsonFile)//根据给定的JSON文件,创建出相应的解码器
for {//遍历JSON文件,直到遇见EOF为止
var post Post err := decoder.Decode(&post)//将JSON数据解码至结构
if err == io.EOF {
break
}
if err != nil {
fmt.Println("Error decoding JSON:", err)
return
}
fmt.Println(post)
}
通过调用NewDecoder
并传入一个包含JSON数据的io.Reader
,程序创建出了一个新的解码器。在把指向Post
结构的引用传递给解码器的Decode
方法之后,被传入的结构就会填充上相应的数据,然后这些数据就可以为程序所用了。当所有JSON数据都被解码完毕时,Decode
方法将会返回一个EOF,而程序则会在检测到这个EOF之后退出for循环。
我们可以通过执行以下命令来运行这个JSON解码器:
go run json.go
如果一切正常,将会看到以下结果:
{1 Hello World! {2 Sau Sheong} [{1 Have a great day! Adam} {2 How are you today? Betty}]}
最后,在面对JSON数据时,我们可以根据输入决定使用Decoder
还是Unmarshal
:如果JSON数据来源于io.Reader
流,如http.Request
的Body,那么使用Decoder
更好;如果JSON数据来源于字符串或者内存的某个地方,那么使用Unmarshal
更好。