Go 解析JSON


  JSON(Javascript Object Notation)是一種輕量級的數據交換語言,以文字為基礎,具有自我描述性且易於讓人閱讀。盡管JSON是JavaScript的一個子集,但JSON是獨立於語言的文本格式,並且采用了類似於C語言家族的一些習慣。JSON與XML最大的不同在於XML是一個完整的標記語言,而JSON不是。JSON由於比XML更小、更快,更易解析,以及瀏覽器的內建快速解析支持,使得其更適用於網絡數據傳輸領域。
解析到結構體
Go的JSON包中有如下函數
// json.go
package main

import (
	"encoding/json"
	"fmt"
)

type Server struct {
	ServerName string
	ServerIP   string
}

type Serverslice struct {
	Servers []Server
}

func main() {
	var s Serverslice
	str := `{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},
			{"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}`

	json.Unmarshal([]byte(str), &s)
	fmt.Println(s)
	fmt.Println(s.Servers[0].ServerIP)

}
outputs:
{[{Shanghai_VPN 127.0.0.1} {Beijing_VPN 127.0.0.2}]}
127.0.0.1
  首先定義了與json數據對應的結構體,數組對應slice,字段名對應JSON里面的KEY,在解析的時候,如何將JSON數據與struct字段相匹配呢?如JSON的key是Foo,那么怎么找對應的字段呢?
  •  首先查找tag含有Foo的可導出的struct字段(首字母大寫)
  • 其次查找字段名是Foo的導出字段
  • 最后查找類似FOO或者FoO這樣的除了首字母之外其他大小寫不敏感的導出字段
  能夠被賦值的字段必須是可導出字段(即首字母大寫)。同時JSON解析的時候只會解析能找到的字段,如果找不到的字段會被忽略,這樣的一個好處是:當你接收到一個很大的JSON數據結構而你卻只想獲取其中的部分數據的時候,你只需將你想要的數據對應的字段名大寫,即可輕松解決問題。
 
解析到interface
  我們知道interface{}可以用來存儲任意數據類型的對象,這種數據結構正好用於存儲解析的未知結構的json數據的結果。JSON包中采用map[string]interface{}和[]interface{}結構來存儲任意的JSON對象和數組。Go類型和JSON類型的對應關系如下:
  • bool代表JSON booleans
  • float64代表JSON numbers
  • string代表JSON strings
  • nil 代表JSON null
通過斷言方式訪問數據,如下例:
// tointer.go
package main

import (
	"encoding/json"
	"fmt"
)

func main() {

	b := []byte(`{"Name":"Wednesday", "Age":6, "Parents": [ "Gomez", "Moticia" ]}`)
	var f interface{}
	err := json.Unmarshal(b, &f)
	if err != nil {
		fmt.Println(err)
	}

	m := f.(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 []interface{}:
			fmt.Println(k, "is an array:")
			for i, u := range vv {
				fmt.Println(i, u)
			}
		default:
			fmt.Println(k, "is of a type I don't know how to handle")
		}
	}

}
outputs:
  Name is string Wednesday
  Age is of a type I don't know how to handle
  Parents is an array:
  0 Gomez
  1 Moticia
通過上面的示例可以看到,通過interface{}與type assert的配合,我們就可以解析未知結構的JSON函數了。
生成JSON
若我們要輸出JSON數據串,可通過Marshal函數來處理
func Marshal(v interface{})([]byte, error)
例:
// generalJson
package main

import (
	"encoding/json"
	"fmt"
)

type Server struct {
	ServerName string `json:"serverName"`
	ServerIP   string `json:"serverIP"`
}

type Serverslice struct {
	Servers []Server `json:"servers"`
}

func main() {

	var s Serverslice
	s.Servers = append(s.Servers, Server{ServerName: "Shanghai_VPN", ServerIP: "127.0.0.1"})
	s.Servers = append(s.Servers, Server{ServerName: "Beijing_VPN", ServerIP: "127.0.0.2"})

	b, err := json.Marshal(s)
	if err != nil {
		fmt.Println("json err: ", err)
	}

	fmt.Println(string(b))

}
outputs:
{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},         {"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}
 
  針對JSON的輸出,我們在定義struct tag的時候需要注意幾點:
  • 字段的tag是“-”,那么這個字段不會輸出到JSON
  • tag中帶有自定義名稱,那么這個自定義名稱會出現在JSON的字段名中,例如上面例子中的serverName
  • tag中如果帶有“omitempty”選項,那么如果該字段值為空,就不會輸出到JSON串中
  • 如果字段類型是bool,string,int,int64等,而tag中帶有“,string”選項,那么這個字段在輸出到JSON的時候會把該字段對應的值轉換成JSON字符串
例:
// jsontest.go
package main

import (
	"encoding/json"
	"os"
)

type Server struct {
	//ID不會導出到JSON
	ID int `json:"-"`

	//ServerName的值會進行二次JSON編碼
	ServerName  string `json:"serverName"`
	ServerName2 string `json:"serverName2, string"`

	//如果ServerIP為空,則不輸出到JSON中
	ServerIP    string `json:"serverIP,omitempty"`
	Description string `json:"description,string"`
}

func main() {

	s := Server{
		ID:          3,
		ServerName:  `Go "1.0"`,
		ServerName2: `Go "1.0"`,
		ServerIP:    ``,
		Description: `描述信息`,
	}

	b, _ := json.Marshal(s)
	os.Stdout.Write(b)

}
outputs:
{"serverName":"Go \"1.0\"","serverName2":"Go \"1.0\""}
 
  Marshal函數只有在轉換成功的時候才會返回數據,在轉換的過程中我們需要注意幾點:
  • JSON對象只支持string作為key,所以要編碼一個map,那么必須是map[string]T這種類型(T是Go語言中任意的類型)
  • Channel,complex和function是不能被編碼成JSON的 
  • 嵌套的數據時不能編碼的,不然會讓JSON編碼進入死循環
  • 指針在編碼的時候會輸出指針指向的內容,而空指針會輸出null
 
  目前bitly公司開源了一個叫做simplejson的包,在處理未知結構體的JSON時相當方便,地址:https://github.com/bitly/go-simplejson
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM