前言
上一次我們一起學習了如何解析接口返回的XML數據,這一次我們一起來學習JSON的解析方法。
JSON(Javascript Object Notation)是一種輕量級的數據交換語言,以文字為基礎,具有自我描述性且易於讓人閱讀。XML是一個完整的標記語言,而JSON不是。JSON比XML更小、更快,更易解析,因此其被廣泛應用於網絡數據傳輸領域。
Go語言的標准庫已經非常好的支持了JSON,可以很容易的對JSON數據進行編、解碼的工作。下面我們通過一些實例一起來學習。
首先我們假設我們的接口返回的JSON數據如下:
{ "code": "00",
"message": "SUCCESS",
"describe": "成功",
"resultInfo": { "uniqueNumber": "201808161133401673324075025000035" }
}
解析到結構體
這種方式與xml解析的方法基本沒有什么區別,我們首先要定義一個結構體,然后調用json.Unmarshal
把數據解析到結構體:
func StructMethod() {
resp := `{"code": "00",
"message": "SUCCESS",
"describe": "成功",
"resultInfo": { "uniqueNumber": "201808161133401673324075025000035" }
}`
type JsonResp struct {
Code int `json:"code"`
Message string `json:"message"`
Describe string `json:"describe"`
ResultInfo map[string]string `json:"resultInfo"`
}
var smsresp JsonResp
temp := []byte(resp)
errs := json.Unmarshal(temp, &smsresp)
if errs != nil {
return
}
fmt.Println(smsresp.Code)
fmt.Println(smsresp.Describe)
fmt.Println(smsresp.Message)
fmt.Println(smsresp.ResultInfo["uniqueNumber"])
}
json數據與struct字段是如何相匹配的呢?
可能有的小伙伴和我一樣好奇,在解析的時候,json數據與struct字段是如何相匹配的呢?例如JSON的key是code,那么怎么找對應的字段呢?
- 首先查找tag含有code的可導出的struct字段(首字母大寫)
- 其次查找字段名是code的導出字段
- 最后查找類似Code或者COde這樣的除了首字母之外其他大小寫不敏感的導出字段
注意: 能夠被賦值的字段必須是可導出字段(即首字母大寫)。同時JSON解析的時候只會解析能找得到的字段,找不到的字段會被忽略。我們在實際使用的過程中一定要隨時警惕這一點。
其實與這個潛在的坑相比,它的優勢非常明顯:當你接收到一個很大的JSON數據結構而你卻只想獲取其中的部分數據的時候,你只需將你想要的數據對應的字段名大寫,即可輕松解決。
解析到interface
上面那種解析方式是在我們知曉被解析的JSON數據的結構的前提下采取的方案,如果我們不知道被解析的數據的格式,又應該如何來解析呢?
Go類型和JSON類型
我們知道interface{}可以用來存儲任意數據類型的對象,這種數據結構正好用於存儲解析的未知結構的json數據的結果。JSON包中采用map[string]interface{}和[]interface{}結構來存儲任意的JSON對象和數組。Go類型和JSON類型的對應關系如下:
類型 | JSON類型 |
---|---|
bool | JSON booleans, |
float64 | JSON numbers, |
string | JSON strings, |
nil | JSON null. |
實例代碼
// InterfaceMethod 方式
func InterfaceMethod() {
resp := `{"code": "00",
"message": "SUCCESS",
"describe": "成功",
"resultInfo": {"uniqueNumber": "201808161133401673324075025000035"}
}`
var x interface{}
_ = json.Unmarshal([]byte(resp), &x)
m := x.(map[string]interface{})
for k, v := range m {
switch vv := v.(type) {
case string:
fmt.Println(k, "is string", vv)
case int:
fmt.Println(k, "is int", vv)
case float64:
fmt.Println(k, "is float64", vv)
case []interface{}:
fmt.Println(k, "is an array:")
for i, u := range vv {
fmt.Println(i, u)
}
case map[string]interface{}:
fmt.Println(k, "is an map[string]string:")
for i, u := range vv {
fmt.Println(i, u)
}
default:
fmt.Println(k, "is of a type didn't handle")
}
}
}
simpleJson
上面兩種方式其實已經能應付我們一般的工作了,但是單純就解析數據而言(這里先買個關子),其實還有一種更簡單的方式,那就是第三方庫:github.com/bitly/go-simplejson
,使用方法如下:
func SimplejsonMethod() {
resp := `{"code": "00",
"message": "SUCCESS",
"describe": "成功",
"resultInfo": { "uniqueNumber": "201808161133401673324075025000035" }
}`
js, errs := NewJson([]byte(resp))
if errs != nil {
return
}
discount := js.Get("resultInfo").Get("uniqueNumber")
strcode, _ := js.Get("code").String()
intcode, _ := js.Get("code").Int()
path := js.GetPath("resultInfo", "uniqueNumber")
fmt.Println(discount)
fmt.Println(strcode)
fmt.Println(intcode)
fmt.Println(path)
}
運行輸出:
bingo@Mac unpackData$ go run JSONparse.go
&{201808161133401673324075025000035}
00
0
&{201808161133401673324075025000035}
GetPath方法是Get的人精簡版,使用結尾調用的方法可以吧輸出的結果轉化為指定的類型(string 00 轉換為 0 )。
那么多個方法的調用怎么完成數據傳遞的呢?輸出結果的&
符號其實已經暴露了它的身份,對就是指針,這個庫每個方法接收和返回的都是指針數據。
總結
- json 解析 到struct
- interface{}與type assert的配合使用
- simplejson
- 學習一門語言是一個慢慢熟悉的過程,初始是不易使用完成度太高的輪子