參考https://studygolang.com/pkgdoc
導入方式:
import "encoding/json"
json包實現了json對象的編解碼,參見RFC 4627。Json對象和go類型的映射關系請參見Marshal和Unmarshal函數的文檔。
參見"JSON and Go"獲取本包的一個介紹:http://golang.org/doc/articles/json_and_go.html
func Unmarshal
func Unmarshal(data []byte, v interface{}) error
Unmarshal函數解析json編碼的數據並將結果存入v指向的值。
Unmarshal和Marshal做相反的操作,必要時申請映射、切片或指針,有如下的附加規則:
要將json數據解碼寫入一個指針,Unmarshal函數首先處理json數據是json字面值null的情況。此時,函數將指針設為nil;否則,函數將json數據解碼寫入指針指向的值;如果指針本身是nil,函數會先申請一個值並使指針指向它。
要將json數據解碼寫入一個結構體,函數會匹配輸入對象的鍵和Marshal使用的鍵(結構體字段名或者它的標簽指定的鍵名),優先選擇精確的匹配,但也接受大小寫不敏感的匹配。
要將json數據解碼寫入一個接口類型值,函數會將數據解碼為如下類型寫入接口:
Bool 對應JSON布爾類型 float64 對應JSON數字類型 string 對應JSON字符串類型 []interface{} 對應JSON數組 map[string]interface{} 對應JSON對象 nil 對應JSON的null
如果一個JSON值不匹配給出的目標類型,或者如果一個json數字寫入目標類型時溢出,Unmarshal函數會跳過該字段並盡量完成其余的解碼操作。如果沒有出現更加嚴重的錯誤,本函數會返回一個描述第一個此類錯誤的詳細信息的UnmarshalTypeError。
JSON的null值解碼為go的接口、指針、切片時會將它們設為nil,因為null在json里一般表示“不存在”。 解碼json的null值到其他go類型時,不會造成任何改變,也不會產生錯誤。
當解碼字符串時,不合法的utf-8或utf-16代理(字符)對不視為錯誤,而是將非法字符替換為unicode字符U+FFFD。
舉例:通過interface{} 與 type assert的配合,這樣就能夠解析未知結構的JSON數了
package main
import(
"fmt" "encoding/json" ) func main() { var s interface{} str := ` { "name" : "testJSON", "servers" : [ { "serverName" : "Shanghai_VPN", "serverIP" : "127.0.0.1" }, { "serverName" : "Beijing_VPN", "serverIP" : "127.0.0.2" } ], "status" : false }` json.Unmarshal([]byte(str), &s) fmt.Println(s) //然后需要通過斷言來將其從interface{}類型轉成map[string]interface{}類型 m := s.(map[string]interface{}) for key, value := range m { switch v := value.(type){//得到s的類型 case string : fmt.Println(key , " is string ", v) case int : fmt.Println(key, "is int", v) case []interface{}: fmt.Println(key, "is an array") for i, vv := range v{ fmt.Println(i, vv) } default: fmt.Println(key, "is of a type i don't know how to handle") } } }
返回:
userdeMBP:go-learning user$ go run test.go
map[name:testJSON servers:[map[serverName:Shanghai_VPN serverIP:127.0.0.1] map[serverName:Beijing_VPN serverIP:127.0.0.2]] status:false] name is string testJSON servers is an array 0 map[serverName:Shanghai_VPN serverIP:127.0.0.1] 1 map[serverIP:127.0.0.2 serverName:Beijing_VPN] status is of a type i don't know how to handle
func Marshal
func Marshal(v interface{}) ([]byte, error)
Marshal函數返回v的json編碼。
Marshal函數會遞歸的處理值。如果一個值實現了Marshaler接口切非nil指針,會調用其MarshalJSON方法來生成json編碼。nil指針異常並不是嚴格必需的,但會模擬與UnmarshalJSON的行為類似的必需的異常。
否則,Marshal函數使用下面的基於類型的默認編碼格式:
布爾類型編碼為json布爾類型。
浮點數、整數和Number類型的值編碼為json數字類型。
字符串編碼為json字符串。角括號"<"和">"會轉義為"\u003c"和"\u003e"以避免某些瀏覽器吧json輸出錯誤理解為HTML。基於同樣的原因,"&"轉義為"\u0026"。
數組和切片類型的值編碼為json數組,但[]byte編碼為base64編碼字符串,nil切片編碼為null。
結構體的值編碼為json對象。每一個導出字段變成該對象的一個成員,除非:
- 字段的標簽是"-" - 字段是空值,而其標簽指定了omitempty選項
空值是false、0、""、nil指針、nil接口、長度為0的數組、切片、映射。對象默認鍵字符串是結構體的字段名,但可以在結構體字段的標簽里指定。結構體標簽值里的"json"鍵為鍵名,后跟可選的逗號和選項,舉例如下:
// 字段被本包忽略 Field int `json:"-"` // 字段在json里的鍵為"myName" Field int `json:"myName"` // 字段在json里的鍵為"myName"且如果字段為空值將在對象中省略掉 Field int `json:"myName,omitempty"` // 字段在json里的鍵為"Field"(默認值),但如果字段為空值會跳過;注意前導的逗號 Field int `json:",omitempty"`
"string"選項標記一個字段在編碼json時應編碼為字符串。它只適用於字符串、浮點數、整數類型的字段。這個額外水平的編碼選項有時候會用於和javascript程序交互:
Int64String int64 `json:",string"`
如果鍵名是只含有unicode字符、數字、美元符號、百分號、連字符、下划線和斜杠的非空字符串,將使用它代替字段名。
匿名的結構體字段一般序列化為他們內部的導出字段就好像位於外層結構體中一樣。如果一個匿名結構體字段的標簽給其提供了鍵名,則會使用鍵名代替字段名,而不視為匿名。
Go結構體字段的可視性規則用於供json決定那個字段應該序列化或反序列化時是經過修正了的。如果同一層次有多個(匿名)字段且該層次是最小嵌套的(嵌套層次則使用默認go規則),會應用如下額外規則:
1)json標簽為"-"的匿名字段強行忽略,不作考慮;
2)json標簽提供了鍵名的匿名字段,視為非匿名字段;
3)其余字段中如果只有一個匿名字段,則使用該字段;
4)其余字段中如果有多個匿名字段,但壓平后不會出現沖突,所有匿名字段壓平;
5)其余字段中如果有多個匿名字段,但壓平后出現沖突,全部忽略,不產生錯誤。
對匿名結構體字段的管理是從go1.1開始的,在之前的版本,匿名字段會直接忽略掉。
映射類型的值編碼為json對象。映射的鍵必須是字符串,對象的鍵直接使用映射的鍵。
指針類型的值編碼為其指向的值(的json編碼)。nil指針編碼為null。
接口類型的值編碼為接口內保持的具體類型的值(的json編碼)。nil接口編碼為null。
通道、復數、函數類型的值不能編碼進json。嘗試編碼它們會導致Marshal函數返回UnsupportedTypeError。
Json不能表示循環的數據結構,將一個循環的結構提供給Marshal函數會導致無休止的循環。
func MarshalIndent
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
MarshalIndent類似Marshal但會使用縮進將輸出格式化。其可讀性更高
package main import( "fmt" "encoding/json" "os" ) type Address struct { City, State string } type Person struct { Id int `json:"id"` //id作為該JSON字段的key值 FirstName string //不設置標簽則默認使用FirstName為字段key值 LastName string `json:"-"` //字段被本包忽略,即使有值也不輸出 Age int `json:",omitempty"` //含omitempty選項的字段如果為空值會省略,如果存在Age作為該JSON字段的key值 Height float32 `json:"height,omitempty"` //含omitempty選項的字段如果為空值會省略,如果存在height作為該JSON字段的key值 Address //匿名字段(其標簽無效)會被處理為其字段是外層結構體的字段,所以沒有Address這個元素,而是直接顯示City, State這兩個元素 } func main() { v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} v.Address = Address{"Hanga Roa", "Easter Island"} output, err := json.MarshalIndent(v, "&", " ")//每行以&作為前綴,並縮進四個空格 if err != nil { fmt.Printf("error: %v\n", err) } os.Stdout.Write(output) }
返回:
userdeMBP:go-learning user$ go run test.go { & "id": 13, & "FirstName": "John", & "Age": 42, & "City": "Hanga Roa", & "State": "Easter Island" &}
如果使用的是Marshal,則返回:
userdeMBP:go-learning user$ go run test.go {"id":13,"FirstName":"John","Age":42,"City":"Hanga Roa","State":"Easter Island"}
未完待續