英文:
Golang unmarshal json map & array
问题
阅读完《JSON和Go》之后,我确实理解了在Go中解码JSON的基础知识。然而,存在一个问题,即输入的JSON有时可以是一个映射,有时可以是一个映射数组。
考虑以下问题:
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")
}
}
现在,我如何在这两种情况(b
和c
)下获取值email: example@test.com
?
问题:
- 如果JSON是一个数组,我想循环遍历每个元素并打印出email。
- 如果JSON是一个映射,我想直接打印出email。
Play链接:http://play.golang.org/p/UPoFxorqWl
英文:
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:
- If json is an array, I want to loop over each & print email.
- if json is an map, I want to print email directly
答案1
得分: 5
根据你的原始解决方案,这里有一个解决你的问题的解决方案,希望能对你有所帮助。
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)
}
}
这段代码使用了encoding/json
包来处理JSON解码。Item
结构体定义了一个Email
字段,使用json:"email"
标签指定了JSON中对应的键名。在main
函数中,首先尝试将JSON解码为单个Item
对象,如果失败则尝试解码为Item
对象的切片。最后,根据解码结果打印出Email
字段的值。
英文:
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)
}
}
答案2
得分: 3
这是你想要的吗?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("这是 b", x.(map[string]interface{})["email"])
}
default:
fmt.Println("未找到类型")
}
json.Unmarshal(c, &m)
switch v := m.(type) {
case map[string]interface{}:
fmt.Println("这是 c", v["email"])
default:
fmt.Println("未找到类型")
}
}
编辑:漏掉了循环部分,已添加。
英文:
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.
答案3
得分: 2
这不是最常用的方法,但另一种方法是尝试将其转换为所需的类型。这种方法的优点是除了所需的反射外,不需要额外的反射。
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 ""
}
英文:
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 ""
}
答案4
得分: 2
你可以尝试使用这个包
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)
}
英文:
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)
}
答案5
得分: 1
惯用的方式:实现Unmarshaler接口:
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
}
使用json.Unmarshal(jsonBytes, location)
解码JSON字节。
email := Email{}
json.Unmarshal(jsonBytes, &email)
或者
emails := []Email{}
json.Unmarshal(jsonBytes, &emails)
英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论