通過Go來分析和建立JSON

go_9發表於2019-01-26

一、分析JSON

首先了解一下JSON的語法規則

JSON 語法是 JavaScript 物件表示語法的子集。

  1. 資料在名稱/值對中
  2. 資料由逗號分隔
  3. 大括號儲存物件
  4. 中括號儲存陣列

把結構對映到JSON只有一個通用規則:對於名字為的JSON鍵,使用者只需要在結構裡建立一個任意名字的欄位,並將該欄位的結構標籤設定為json:"<name>",就可以把JSON鍵的值儲存到這個欄位裡面。

下面是要分析的JSON檔案

{
  "id":1,
  "content":"Hello World",
  "author":{
    "id":2,
    "name":"Sau She"
  },
  "comments":[
    {
      "id":3,
      "content":"Have a great day!",
      "author":"Adam"
    },
    {
      "id":4,
      "content":"How are you today!",
      "author":"Betty"
    }
  ]
}

下面給出分析程式

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "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() {
    file, err := os.Open("src/text/json/post.json")
    if err != nil {
        log.Fatalf("Error opening JSON file %v",err)
        return
    }
    defer file.Close()
    bytes, err := ioutil.ReadAll(file)
    if err != nil {
        log.Fatalf("Error reading JSON file %v",err)
        return
    }
    var post Post
    json.Unmarshal(bytes,&post)
    fmt.Println(post)
}

使用者出了可以用Unmarshal函式來解封JSON,還可以使用Decoder手動地將JSON資料解碼到結構體裡面,以此來處理流式的JSON資料。

package main

import (
    "encoding/json"
    "io"
    "log"
    "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() {
    file, err := os.Open("src/text/json/post.json")
    if err != nil {
        log.Fatalf("Error opening JSON file %v",err)
        return
    }
    defer file.Close()
    decoder := json.NewDecoder(file)
    for  {
        var post Post
        err := decoder.Decode(&post)
        if err == io.EOF {
            break
        }
        if err != nil{
            log.Fatalf("Error decoding JSON  %v",err)
            return
        }
    }
}

最後,在面對JSON資料時,我們可以根據輸入決定使用Decode還是Unmarshal:如果JSON資料來源是io.Reader流,如http.Request的Body,那麼使用Decoder更好;如果JSON資料來源於字串或者是記憶體的某個地方,那麼使用Unmarshal更好。

二、建立JSON

package main

import (
    "encoding/json"
    "io/ioutil"
    "log"
)

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() {
    post := Post{
        Id:1,
        Content:"Hello World!",
        Author:Author{
            Id:2,
            Name:"Sau Sheong",
        },
        Comments: []Comment{{
            Id:1,
            Content:"i love sz",
            Author:"zhu",
        },{
            Id:2,
            Content:"i love sh",
            Author:"liu",
        }},
    }
    output, err := json.MarshalIndent(&post,"","\t")
    if err != nil {
        log.Fatalf("Error marshalling to JSON  %v",err)
        return
    }
    err = ioutil.WriteFile("src/text/json/post2.json",output,0644)
    if err != nil {
        log.Fatalf("Error writing JSON to file  %v",err)
        return
    }
}

讓我看看post2.json檔案裡面的內容

{
    "id": 1,
    "content": "Hello World!",
    "author": {
        "id": 2,
        "name": "Sau Sheong"
    },
    "comments": [
        {
            "id": 1,
            "content": "i love sz",
            "author": "zhu"
        },
        {
            "id": 2,
            "content": "i love sh",
            "author": "liu"
        }
    ]
}

我們也可通過編碼器手動將Go結構編碼為JSON資料。

package main

import (
    "encoding/json"
    "log"
    "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() {
    post := Post{
        Id:1,
        Content:"Hello World!",
        Author:Author{
            Id:2,
            Name:"Sau Sheong",
        },
        Comments: []Comment{{
            Id:1,
            Content:"i love sz",
            Author:"zhu",
        },{
            Id:2,
            Content:"i love sh",
            Author:"liu",
        }},
    }
    jsonFile, err := os.Create("src/text/json/post3.json")
    if err != nil {
        log.Fatalf("Error Create JSON to file  %v",err)
        return
    }
    encoder := json.NewEncoder(jsonFile)
    encoder.SetIndent("","\t")
    encoder.Encode(&post)
    if err != nil {
        log.Fatalf("Error encoding JSON to file  %v",err)
        return
    }
}

程式會建立一個用於儲存JSON資料的JSON檔案,並通過把這個檔案傳遞給NewEncoder函式來建立一個編碼器。接著,程式會呼叫編碼器的Encode方法,並向其傳遞一個指向Post結構的引用。在此以後,Encode方法會從結構裡面提取資料並將其編碼為JSON資料,然後把這些JSON資料寫入到檔案裡面。

相關文章