I have two json files with following structure
{
"cast": [
{
"url": "carey-mulligan",
"name": "Carey Mulligan",
"role": "Actress"
},
{
"url": "leonardo-dicaprio",
"name": "Leonardo DiCaprio",
"role": "Actor"
},
.
.
.
]
}
and
{
"movie": [
{
"url": "carey-mulligan",
"name": "Carey Mulligan",
"role": "Actress"
},
{
"url": "leonardo-dicaprio",
"name": "Leonardo DiCaprio",
"role": "Actor"
},
.
.
.
]
}
as you can see internal structure of the json is same for cast and movie. I want to unmarshel these json file into the same golang structure. But i am not able to give two name tags (cast and movie) for same struct element. I want something like
type Detail struct {
Name string `json:"name"`
Url string `json:"url"`
Role string `json:"role"`
}
type Info struct {
Detail []Detail `json:"cast or movie"`
}
In which case Detail could parse both cast and movie.
Here is my current code
// 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"
}
but it only works for first tag "cast" and gives nill in case json contain the movie.
Thanks in advance.
You can use type Info map[string][]Detail
instead of your struct. Try it on the Go playground
Or you can use both types in your structure, and make method Details()
which will return right one:
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
}
Try it on the Go playground
If you dig far enough down into encoding/json
you'll get to https://github.com/golang/go/blob/master/src/encoding/json/encode.go and the following:
tag := sf.Tag.Get("json")
if tag == "-" {
continue
}
So it gets one json tag and keeps on going.
You could always go with RoninDev's solution and just copy it over when done.
Try anonymous field in struct:
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
", &cInfo)
fmt.Printf("err: %v
", err)
fmt.Printf("details: %v
", cInfo.getDetails())
var mInfo Info
err = json.Unmarshal(movie, &mInfo)
fmt.Printf("movie: %+v
", &mInfo)
fmt.Printf("err: %v
", err)
fmt.Printf("details: %v
", mInfo.getDetails())
}
Things to note: