因为UserName字段,实际上是在使用的时候,才会用到他的具体类型,因此我们可以延迟解析。使用json.RawMessage方式,将json的字串继续以byte数组方式存在。
type User struct { UserName json.RawMessage `json:"username"` Password string `json:"password"` Email string Phone int64 } var jsonString string = `{ "username":"18512341234@qq.com", "password":"123" }` func Decode(r io.Reader) (u *User, err error) { u = new(User) if err = json.NewDecoder(r).Decode(u); err != nil{ return } var email string if err = json.Unmarshal(u.UserName, &email); err == nil{ u.Email = email return } var phone int64 if err = json.Unmarshal(u.UserName, &phone); err == nil{ u.Phone = phone } return } func main() { user, err := Decode(strings.NewReader(jsonString)) if err != nil { log.Fatalln(err) } fmt.Printf("%#v\n", user) }总体而言,延迟解析和使用空接口的方式类似。需要再次调用Unmarshal方法,对json.RawMessage进行解析。原理和解析到接口的形式类似。
不定字段解析对于未知json结构的解析,不同的数据类型可以映射到接口或者使用延迟解析。有时候,会遇到json的数据字段都不一样的情况。例如需要解析下面一个json字串:
接口配合断言 var jsonString string = `{ "things": [ { "name": "Alice", "age": 37 }, { "city": "Ipoh", "country": "Malaysia" }, { "name": "Bob", "age": 36 }, { "city": "Northampton", "country": "England" } ] }`json字串的是一个对象,其中一个key things的值是一个数组,这个数组的每一个item都未必一样,大致是两种数据结构,可以抽象为person和place。即,定义下面的结构体:
type Person struct { Name string `json:"name"` Age int `json:"age"` } type Place struct { City string `json:"city"` Country string `json:"country"` }接下来我们Unmarshal json字串到一个map结构,然后迭代item并使用type断言的方式解析数据:
func decode(jsonStr []byte) (persons []Person, places []Place) { var data map[string][]map[string]interface{} err := json.Unmarshal(jsonStr, &data) if err != nil { fmt.Println(err) return } for i := range data["things"] { item := data["things"][i] if item["name"] != nil { persons = addPerson(persons, item) } else { places = addPlace(places, item) } } return }迭代的时候会判断item是否是person还是place,然后调用对应的解析方法:
func addPerson(persons []Person, item map[string]interface{}) []Person { name := item["name"].(string) age := item["age"].(float64) person := Person{name, int(age)} persons = append(persons, person) return persons } func addPlace(places []Place, item map[string]interface{})([]Place){ city := item["city"].(string) country := item["country"].(string) place := Place{City:city, Country:country} places = append(places, place) return places }最后调用和输出如下:
func main() { personsA, placesA := decode([]byte(jsonString)) fmt.Printf("%+v\n", personsA) fmt.Printf("%+v\n", placesA) } /usr/local/go/bin/go run /Users/ghost/Rsj217/go/src/demo/main.go [{Name:Alice Age:37} {Name:Bob Age:36}] [{City:Ipoh Country:Malaysia} {City:Northampton Country:England}] 混合结构混合结构很好理解,如同我们前面解析username为 email和phone两种情况,就在结构中定义好这两种结构即可。
type Mixed struct { Name string `json:"name"` Age int `json:"age"` city string `json:"city"` Country string `json:"country"` }混合结构的思路很简单,借助golang会初始化没有匹配的json和抛弃没有匹配的json,给特定的字段赋值。比如每一个item都具有四个字段,只不过有的会匹配person的json数据,有的则是匹配place。没有匹配的字段则是零值。接下来在根据item的具体情况,分别赋值到对于的Person或Place结构。
func decode(jsonStr []byte) (persons []Person, places []Place) { var data map[string][]Mixed err := json.Unmarshal(jsonStr, &data) if err != nil { fmt.Println(err) return } fmt.Printf("%+v\n", data["things"]) for i := range data["things"] { item := data["things"][i] if item.Name != "" { persons = append(persons, Person{Name: item.Name, Age: item.Age}) } else { places = append(places, Place{City: item.city, Country: item.Country}) } } return }混合结构的解析方式也很不错。思路还是借助了解析json中抛弃不要的字段,借助零值处理。
json.RawMessagejson.RawMessage非常有用,延迟解析也可以使用这个样例。我们已经介绍过类似的技巧,下面就贴代码了:
func addPerson(item json.RawMessage, persons []Person)([]Person){ person := Person{} if err := json.Unmarshal(item, &person); err != nil{ fmt.Println(err) }else{ if person != *new(Person){ persons = append(persons, person) } } return persons } func addPlace(item json.RawMessage, places []Place)([]Place){ place :=Place{} if err := json.Unmarshal(item, &place); err != nil{ fmt.Println(err) }else{ if place != *new(Place){ places = append(places, place) } } return places } func decode(jsonStr []byte)(persons []Person, places []Place){ var data map[string][]json.RawMessage err := json.Unmarshal(jsonStr, &data) if err != nil{ fmt.Println(err) return } for _, item := range data["things"]{ persons = addPerson(item, persons) places = addPlace(item, places) } return }