【问题标题】:How to unmarshal two json with same internal structure into one single golang struct?如何将具有相同内部结构的两个 json 解组为一个单一的 golang 结构?
【发布时间】:2015-10-21 18:45:05
【问题描述】:

我有两个结构如下的 json 文件

{
 "cast": [
        {
            "url": "carey-mulligan",
            "name": "Carey Mulligan",
            "role": "Actress"
        },
        {
            "url": "leonardo-dicaprio",
            "name": "Leonardo DiCaprio",
            "role": "Actor"
        },
        .
        .
        .
         ]
}

{
 "movie": [
        {
            "url": "carey-mulligan",
            "name": "Carey Mulligan",
            "role": "Actress"
        },
        {
            "url": "leonardo-dicaprio",
            "name": "Leonardo DiCaprio",
            "role": "Actor"
        },
        .
        .
        .
         ]
}

你可以看到 json 的内部结构对于演员和电影是相同的。我想将这些 json 文件解组到相同的 golang 结构中。但我无法为同一个结构元素提供两个名称标签(演员表和电影)。我想要类似的东西

type Detail struct {
    Name string `json:"name"`
    Url  string `json:"url"`
    Role string `json:"role"`
}

type Info struct {
    Detail []Detail `json:"cast or movie"`
}

在这种情况下,Detail 可以解析演员和电影。

这是我当前的代码

// RIMAGE project main.go
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
)

const (
    website = "https://data.moviebuff.com/"
)

func main() {
    fmt.Println("Hello World!")
    content, err := ioutil.ReadFile("data/great-getsby")
    if err != nil {
        panic(err)
    }

    var info Info

    err = json.Unmarshal(content, &info)
    if err != nil {
        panic(err)
    }

    fmt.Println(info.Detail)
}

type Detail struct {
    Name string `json:"name"`
    Url  string `json:"url"`
    Role string `json:"role"`
}

type Info struct {
    Detail []Detail `json:"cast" json:"movie"
}

但它只适用于第一个标签“演员”,如果 json 包含电影,则返回 nill。

提前致谢。

【问题讨论】:

    标签: json encoding go


    【解决方案1】:

    您可以使用type Info map[string][]Detail 代替您的结构。 在 Go playground

    上试试

    或者你可以在你的结构中使用这两种类型,并创建方法Details(),它将返回正确的一个:

    type Info struct {
        CastDetails  []Detail `json:"cast"`
        MovieDetails []Detail `json:"movie"`
    }
    
    func (i Info) Details() []Detail {
        if i.CastDetails == nil {
            return i.MovieDetails
        }
        return i.CastDetails
    }
    

    Go playground

    上试试

    【讨论】:

    • 对不起,它不起作用。结果和以前一样。 play.golang.org/p/dgmINCngD-
    • 对不起,这是我的错,我的第一个版本不正确。编辑了我的答案
    • 您的第一个解决方案对我没有用,因为我的实际信息结构也包含其他字段。第二个解决方案是我想要避免的。
    • 另一种丑陋的方法是 string.replace 字段名:)
    【解决方案2】:

    尝试结构中的匿名字段:

    package main
    
    import (
        "encoding/json"
        "fmt"
        "io/ioutil"
    )
    
    type Detail struct {
        Name string `json:"name"`
        Url  string `json:"url"`
        Role string `json:"role"`
    }
    
    type Cast struct {
        Detail []Detail `json:"cast"`
    }
    
    type Movie struct {
        Detail []Detail `json:"movie"`
    }
    
    type Info struct {
        Cast
        Movie
    }
    
    func (i *Info) getDetails() []Detail {
        if len(i.Cast.Detail) > 0 {
            return i.Cast.Detail
        }
        return i.Movie.Detail
    }
    
    func main() {
        cast, _ := ioutil.ReadFile("./cast.json")
        movie, _ := ioutil.ReadFile("./movie.json")
    
        var cInfo Info
        err := json.Unmarshal(cast, &cInfo)
        fmt.Printf("cast: %+v\n", &cInfo)
        fmt.Printf("err: %v\n", err)
        fmt.Printf("details: %v\n", cInfo.getDetails())
    
        var mInfo Info
        err = json.Unmarshal(movie, &mInfo)
        fmt.Printf("movie: %+v\n", &mInfo)
        fmt.Printf("err: %v\n", err)
        fmt.Printf("details: %v\n", mInfo.getDetails())
    }
    

    注意事项:

    • 另一个间接级别:要访问“详细信息”字段,您需要先访问“信息”中的“演员”或“电影”字段。
    • 更好地为'Details'提供访问功能(本例中为'getDetail')

    【讨论】:

      【解决方案3】:

      如果您深入了解encoding/json,您将到达https://github.com/golang/go/blob/master/src/encoding/json/encode.go 和以下内容:

              tag := sf.Tag.Get("json")
              if tag == "-" {
                  continue
              }
      

      所以它得到一个 json 标签并继续运行。

      您总是可以使用 RoninDev 的解决方案,完成后将其复制过来。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-12
        • 2017-04-25
        • 2023-02-23
        • 2020-02-01
        • 1970-01-01
        • 2018-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多