分析JSON的步骤和分析XML的步骤基本相同——分析程序首先要做的就是把JSON的分析结果存储到一些结构里面,然后通过访问这些结构来提取数据。下面是分析JSON的两个常见步骤(这个过程如图7-7所示):

图7-7 使用Go分析JSON:创建结构并将JSON解封到结构里面

  1. 创建一些用于包含JSON数据的结构;
  2. 通过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更好。

results matching ""

    No results matching ""