简体   繁体   English

Golang解组JSON地图和数组

[英]Golang unmarshal json map & array

After reading JSON and Go , I do understand the basics of decoding json in Go are. 阅读JSON和Go之后 ,我了解了Go中解码json的基础。 However, there this problem where that input json can be sometimes a map & sometimes an array of maps. 但是,存在一个问题,即输入json有时可能是地图,有时可能是地图数组。

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 ) 现在,在两种情况下我如何获得email的值: example@test.combc

Question: 题:

  1. If json is an array, I want to loop over each & print email. 如果json是一个数组,我想遍历每个&打印电子邮件。
  2. if json is an map, I want to print email directly 如果json是地图,我想直接打印电子邮件

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

In my experience, using interface{} to handle json decoding may cause some strange problem, which I tend to avoid it. 以我的经验,使用interface {}处理json解码可能会导致一些奇怪的问题,我倾向于避免这种情况。 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 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 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: 惯用的方式:实现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
}

Use " json.Unmarshal(jsonBytes, location) " to decode json bytes. 使用“ json.Unmarshal(jsonBytes,location) ”解码json字节。

email := Email{}
json.Unmarshal(jsonBytes, &email)

OR 要么

emails := []Email{}
json.Unmarshal(jsonBytes, &emails)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM