Golang解析JSON的map和数组。

huangapple go评论82阅读模式
英文:

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")
	}

}

现在,我如何在这两种情况(bc)下获取值email: example@test.com

问题:

  1. 如果JSON是一个数组,我想循环遍历每个元素并打印出email。
  2. 如果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:

  1. If json is an array, I want to loop over each & print email.
  2. if json is an map, I want to print email directly

Play: http://play.golang.org/p/UPoFxorqWl

答案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)

huangapple
  • 本文由 发表于 2016年2月29日 12:05:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/35691811.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定