After reading JSON and Go , I do understand the basics of decoding json in Go are. However, there this problem where that input json can be sometimes a map & sometimes an array of maps.
consider the following problem:
package main
import (
"encoding/json"
"fmt"
)
func main() {
b := []byte(`[{"email":"example@test.com"}]`)
c := []byte(`{"email":"example@test.com"}`)
var m interface{}
json.Unmarshal(b, &m)
switch v := m.(type) {
case []interface{}:
fmt.Println("this is b", v)
default:
fmt.Println("No type found")
}
json.Unmarshal(c, &m)
switch v := m.(type) {
case map[string]interface{}:
fmt.Println("this is c", v)
default:
fmt.Println("No type found")
}
}
Now, how to I get to the value email
: example@test.com
in both cases( b
& c
)
Question:
In my experience, using interface{} to handle json decoding may cause some strange problem, which I tend to avoid it. Although there are ways to achieve it using the reflect package.
Here is a solution for you problem base on your origin solution, hope it helps.
package main
import (
"encoding/json"
"fmt"
)
type Item struct {
Email string `json:email`
}
func main() {
b := []byte(`[{"email":"example_in_array@test.com"}]`)
//b := []byte(`{"email":"example@test.com"}`)
var m = &Item{}
var ms = []*Item{}
err := json.Unmarshal(b, &m)
if err != nil {
err = json.Unmarshal(b, &ms)
if err != nil {
panic(err)
}
for _, m := range ms {
fmt.Println(m.Email)
}
} else {
fmt.Println(m.Email)
}
}
Is this what you wanted? http://play.golang.org/p/8yrirlUAnp
package main
import (
"encoding/json"
"fmt"
)
func main() {
b := []byte(`[{"email":"example@test.com"}]`)
c := []byte(`{"email":"example@test.com"}`)
var m interface{}
json.Unmarshal(b, &m)
switch v := m.(type) {
case []interface{}:
for _, x := range v {
fmt.Println("this is b", x.(map[string]interface{})["email"])
}
default:
fmt.Println("No type found")
}
json.Unmarshal(c, &m)
switch v := m.(type) {
case map[string]interface{}:
fmt.Println("this is c", v["email"])
default:
fmt.Println("No type found")
}
}
Edit: missed the loop part, added it.
This is not the most idiomatic, but another way to do it is to try and marshal into the type that you want. The advantage here is there is no extra reflection beyond what is needed.
http://play.golang.org/p/dV5qCu3tKk
package main
import (
"encoding/json"
"fmt"
)
func main() {
fmt.Println(extract([]byte(`[{"email":"example@test.com"}]`)))
fmt.Println(extract([]byte(`{"email":"example@test.com"}`)))
}
func extract(b []byte) string {
var m map[string]string
err := json.Unmarshal(b, &m)
if err == nil {
return m["email"]
}
var nested []map[string]string
err = json.Unmarshal(b, &nested)
if err == nil {
for _, m := range nested {
return m["email"]
}
}
return ""
}
You can try this package
b := []byte(`[{"email":"example@test.com"}]`)
c := []byte(`{"email":"example@test.com"}`)
var m interface{}
var mm interface{}
json.Unmarshal(b, &m)
json.Unmarshal(c, &mm)
x := map[string]interface{}{
"wrapped": m,
}
xx := map[string]interface{}{
"wrapped": mm,
}
var email string
if email_interface, err := GetProperty(x, "wrapped[0].email"); err == nil {
email, _ = email_interface.(string)
}
if email_interface, err := GetProperty(xx, "wrapped.email"); err == nil {
email, _ = email_interface.(string)
}
The Idiomatic way: implement Unmarshaler interface:
type Email struct {
Val string `json:"email"`
}
func (this *Email) UnmarshalJSON(jsonBytes []byte) error {
var err error
type EmailStruct Email
bytesBuffer := bytes.Buffer{}
if jsonBytes[0] == '[' {
emails := []EmailStruct{}
err = json.Unmarshal(jsonBytes, &emails)
if err != nil {
return err
}
encoder := gob.NewEncoder(&bytesBuffer)
err = encoder.Encode(&emails[0])
if err != nil {
return err
}
decoder := gob.NewDecoder(&bytesBuffer)
err = decoder.Decode(this)
if err != nil {
return err
}
return err
}
email := EmailStruct{}
err = json.Unmarshal(jsonBytes, &email)
if err != nil {
return err
}
encoder := gob.NewEncoder(&bytesBuffer)
err = encoder.Encode(&email)
if err != nil {
return err
}
decoder := gob.NewDecoder(&bytesBuffer)
err = decoder.Decode(this)
if err != nil {
return err
}
return err
}
Use " json.Unmarshal(jsonBytes, location) " to decode json bytes.
email := Email{}
json.Unmarshal(jsonBytes, &email)
OR
emails := []Email{}
json.Unmarshal(jsonBytes, &emails)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.