Golang JSON操做彙總

直接把結構體編碼成json數據

package main import ( "encoding/json" "fmt" _ "os" ) type Address struct { Type string City string Country string } type Card struct { Name string Age int Addresses []*Address } func main() { pa := &Address{"private", "Shanghai", "China"} pu := &Address{"work", "Beijing", "China"} c := Card{"Xin", 32, []*Address{pa, pu}} js, _ := json.Marshal(c) fmt.Printf("Json: %s", js) } 

利用json.Marshal,可將結構體轉爲JSON數據:golang

Json: {"Name":"Xin","Age":32,"Addresses":[{"Type":"private","City":"Shanghai","Country":"China"},{"Type":"work","City":"Beijing","Country":"China"}]} 

json.MarshalIndent(c, "", " ")能夠將json代碼格式化:web

Json: { "Name": "Xin", "Age": 32, "Addresses": [ { "Type": "private", "City": "Shanghai", "Country": "China" }, { "Type": "work", "City": "Beijing", "Country": "China" } ] } 

Tips

  1. 在 web 應用中最好使用json.MarshalforHTML()函數,會對數據執行HTML轉碼。
  2. map 的 key 必須是字符串類型。
  3. Channel,複雜類型和函數類型不能被編碼。
  4. 指針能夠被編碼,其實是對指針指向的值進行編碼.

解碼到數據結構

若是事先知道 JSON 數據的結構,能夠事先定義一個結構來存儲反序列化後的結果。如,對這樣一段 json:json

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

咱們定義這樣一個數據結構:數組

type FamilyMember struct { Name string Age int Parents []string } 

而後能夠將其反序列化:緩存

var m FamilyMember err := json.Unmarshal(b, &m) 

完整的程序:數據結構

package main import ( "encoding/json" "fmt" ) type FamilyMember struct { Name string Age int Parents []string } func main() { b := []byte(`{"Name": "Wednesday", "Age": 6, "Parents": ["Gomez", "Morticia"]}`) var m FamilyMember // json.Unmarshal 用於解碼 json 串 err := json.Unmarshal(b, &m) if err == nil { fmt.Printf("name: %s\nAge: %d\nParents: %v\n", m.Name, m.Age, m.Parents) } } 

執行後輸出:ide

name: Wednesday
Age: 6
Parents: [Gomez Morticia]

解碼任意數據

json 包使用 map[string]interface{} 和 []interface{} 儲存任意的 JSON 對象和數組。一樣是上面的 JSON 串:函數

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

用下面的代碼進行解碼:ui

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

會獲得:編碼

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

對於這類的數據,可使用switch來判斷節點的類型來遍歷數據。



動態更改JSON Sprintf

Golang中使用 fmt.Sprintf 格式化 `JSON Data %s %d %f` 動態變動JSON數據.

其等效做用是, 採用struct轉換, 更改結構體數據, 而後Marshal成JSON, 用於 http處理

JSON數據, 其中 %s 是佔位符: 
   
   
   
   
const jsonRes = ` { "server": { "name": "ty", "imageRef": "f9436296-854f-4fe2-939d-eb667b245b78", "fmtSprintf": "%s", "max_count": 1, "min_count": 1, "networks": [ { "uuid": "1e16b87f-ef66-4f0d-ba3d-d93234159076" } ], "metadata": { "ENV1": "100", "ENV2": "1000", "entrypoint": "/bin/sh -c 'while true; do echo hello world; sleep 99999d; done'" } } } `

使用 fmt. Sprintf  格式化內容, 注意Sprintf返回格式化結果, 須要賦值給變量使用:
   
   
   
   
func fmtSprintfJson() error { //var datm map[string]interface{} var datm interface{} const jsonRes = ` { "server": { "name": "ty", "imageRef": "f9436296-854f-4fe2-939d-eb667b245b78", "fmtSprintf": "%s", "max_count": 1, "min_count": 1, "networks": [ { "uuid": "1e16b87f-ef66-4f0d-ba3d-d93234159076" } ], "metadata": { "ENV1": "100", "ENV2": "1000", "entrypoint": "/bin/sh -c 'while true; do echo hello world; sleep 99999d; done'" } } } ` jsonResSprintf := fmt.Sprintf(jsonRes, "test") fmt.Println("jsonResSprintf = ", jsonResSprintf) err := json.Unmarshal([]byte(jsonResSprintf), &datm) if err != nil { fmt.Println("json.Unmarshal([]byte(json), createRequests) , Error : ", err) return err } fmt.Println("struct request = ", datm) return nil}



和 stream 中 JSON 打交道

上面全部的 JSON 數據來源都是預先定義的 []byte 緩存,在不少時候,若是能讀取/寫入其餘地方的數據就行了。encoding/json 庫中有兩個專門處理這個事情的結構:Decoder和 Encoder

// Decoder 從 r io.Reader 中讀取數據,`Decode(v interface{})` 方法把數據轉換成對應的數據結構
func NewDecoder(r io.Reader) *Decoder

// Encoder 的 `Encode(v interface{})` 把數據結構轉換成對應的 JSON 數據,而後寫入到 w io.Writer 中
func NewEncoder(w io.Writer) *Encoder

下面的例子就是從標準輸入流中讀取數據,解析成數據結構,刪除全部鍵不是 Name 的字段,而後再 encode 成 JSON 數據,打印到標準輸出。

package main

import (
    "encoding/json"
    "log"
    "os"
)

func main() {
    dec := json.NewDecoder(os.Stdin)
    enc := json.NewEncoder(os.Stdout)
    for {
        var v map[string]interface{}
        if err := dec.Decode(&v); err != nil {
            log.Println(err)
            return
        }
        for k := range v {
            if k != "Name" {
                delete(v, k)
            }
        }
        if err := enc.Encode(&v); err != nil {
            log.Println(err)
        }
    }
}


更多控制:Tag  

在定義 struct 字段的時候,能夠在字段後面添加 tag,來控制 encode/decode 的過程:是否要 decode/encode 某個字段,JSON 中的字段名稱是什麼。

能夠選擇的控制字段有三種:

  • -:不要解析這個字段
  • omitempty:當字段爲空(默認值)時,不要解析這個字段。好比 false、0、nil、長度爲 0 的 array,map,slice,string
  • FieldName:當解析 json 的時候,使用這個名字

舉例來講吧:

// 解析的時候忽略該字段。默認狀況下會解析這個字段,由於它是大寫字母開頭的
Field int   `json:"-"`

// 解析(encode/decode) 的時候,使用 `other_name`,而不是 `Field`
Field int   `json:"other_name"`

// 解析的時候使用 `other_name`,若是struct 中這個值爲空,就忽略它
Field int   `json:"other_name,omitempty"`


延遲解析:json.RawMessage  

在解析的時候,還能夠把某部分先保留爲 JSON 數據不要解析,等到後面獲得更多信息的時候再去解析。繼續拿 User 舉例,好比咱們要添加認證的信息,認證能夠是用戶名和密碼,也能夠是 token 認證。

type BasicAuth struct {
    Email string
    Password string
}

type TokenAuth struct {
    Token string
}

type User struct {
    Name string
    IsAdmin bool
    Followers uint
    Auth json.RawMessage
}

咱們在定義 User 結構體的時候,把認證字段的類型定義爲 json.RawMessage,這樣解析 JSON 數據的時候,對應的字段會先不急着轉換成 Go 數據結構。而後咱們能夠本身去再次調用 Unmarshal 去讀取裏面的值:

   
   
   
   
data := []byte(`{"Name":"cizixs","IsAdmin":true,"Followers":36}`)err := json.Unmarshal(data, &basicAuth)if basicAuth.Email != "" { // 這是用戶名/密碼認證方式,在這裏繼續作一些處理} else { json.Unmarshal(data, &tokenAuth) if tokenAuth.Token != "" { // 這是 token 認證方法 }}

 
 


自定義解析方法  

若是但願本身控制怎麼解析成 JSON,或者把 JSON 解析成自定義的類型,只須要實現對應的接口(interface)。encoding/json 提供了兩個接口:Marshaler 和 Unmarshaler

// Marshaler 接口定義了怎麼把某個類型 encode 成 JSON 數據
type Marshaler interface {
        MarshalJSON() ([]byte, error)
}

// Unmarshaler 接口定義了怎麼把 JSON 數據 decode 成特定的類型數據。若是後續還要使用 JSON 數據,必須把數據拷貝一份
type Unmarshaler interface {
        UnmarshalJSON([]byte) error
}

標準庫 time.Time 就實現了這兩個接口。另一個簡單的例子(這個例子來自於參考資料中 Go and JSON 文章):

type Month struct {
    MonthNumber int
    YearNumber int
}

func (m Month) MarshalJSON() ([]byte, error){
    return []byte(fmt.Sprintf("%d/%d", m.MonthNumber, m.YearNumber)), nil
}

func (m *Month) UnmarshalJSON(value []byte) error {
    parts := strings.Split(string(value), "/")
    m.MonthNumber = strconv.ParseInt(parts[0], 10, 32)
    m.YearNumber = strconv.ParseInt(parts[1], 10, 32)

    return nil
}











相關文章
相關標籤/搜索