英文:
How to unmarshal nested json to a struct, if the outer element is not the same in GO
问题
你好,我想知道是否可能将给定的 JSON 反序列化为一个结构体。
type Movie struct {
Title string
Actors []string
ID int
Length int
ReleaseDate string
}
这是一个 JSON 的示例:
{
"movies": [
{
"movie_title_A": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>...."
]
},
"ID": 99992,
"length": 120,
"releaseDate": "2.10.2012"
},
{
"movie_title_B": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>...."
]
},
"ID": 123124,
"length": 90,
"releaseDate": "10.10.2012"
}
]
}
如你所见,Name 字段可以采用任何名称,因为它是电影的标题。是否有一种高效的方法将其放入上述结构体中?任何帮助都将不胜感激,谢谢。
英文:
Hi i wonder if it is possible to unmarshal this given json to a struct
type Movie struct {
Title string
Actors []string
ID int
Length int
RelaseDate string
}
Here is an example of the json
{
"movies": [
{
"movie_title_A": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>...."
]
},
"ID": 99992,
"length": 120,
"relaseDate": "2.10.2012"
},
{
"movie_title_B": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>...."
]
},
"ID": 123124,
"length": 90,
"relaseDate": "10.10.2012"
}
]
}
As you can see the Name field can take on any name, since it is the title of the movie. Is there an efficient way to put it into the struct above?
Any help would be nice, thanks
答案1
得分: 0
给定它的动态性,使用map[string]interface可能更容易,因为您无法定义动态键,例如asd123和2movie23123。
package main
import (
"encoding/json"
"fmt"
)
const j = `{
"movies": [
{
"asd123": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>"
]
},
"ID": 99992,
"length": 120,
"relaseDate": "2.10.2012"
},
{
"2movie23123": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>"
]
},
"ID": 123124,
"length": 90,
"relaseDate": "10.10.2012"
}
]
}`
// Movies ...
type Movies struct {
Name string
ID float64
Length float64
ReleaseDate string
Actors []interface{}
}
func main() {
data := map[string]interface{}{}
err := json.Unmarshal([]byte(j), &data)
if err != nil {
panic(err)
}
var myMovies []Movies
for _, d := range data {
temp := Movies{}
converting := d.([]interface{})
for _, movie := range converting {
convertingMovie := movie.(map[string]interface{})
temp.Length = convertingMovie["length"].(float64)
temp.ID = convertingMovie["ID"].(float64)
temp.ReleaseDate = convertingMovie["relaseDate"].(string)
delete(convertingMovie, "length")
delete(convertingMovie, "ID")
delete(convertingMovie, "relaseDate")
for key, val := range convertingMovie {
temp.Name = key
actors := val.(map[string]interface{})
temp.Actors = actors["actors"].([]interface{})
}
}
myMovies = append(myMovies, temp)
}
b, _ := json.MarshalIndent(myMovies, "", " ")
fmt.Println(string(b))
}
上面的方法可能有更好的实现方式,但我提供了一个快速示例。最好的方法是更好地组织JSON数据,使其更适合结构体,否则可以使用反射。不需要太多工作,我会使用上面的for循环,并将其添加到一个对我来说有意义且可以更轻松访问数据的结构体中。考虑上面是JSON解析器的开始,现在您可以访问JSON数据,将其适应到一个结构体中,然后重新排列数据。
英文:
given it's dynamic nature it might be easier use a map[string]interface as you'll not be able to define dynamic keys like asd123 and 2movie23123.
package main
import (
"encoding/json"
"fmt"
)
const j = `{
"movies": [
{
"asd123": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>"
]
},
"ID": 99992,
"length": 120,
"relaseDate": "2.10.2012"
},
{
"2movie23123": {
"actors": [
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>",
"<actorID1123123>"
]
},
"ID": 123124,
"length": 90,
"relaseDate": "10.10.2012"
}
]
}`
// Movies ...
type Movies struct {
Name string
ID float64
Length float64
ReleaseDate string
Actors []interface{}
}
func main() {
data := map[string]interface{}{}
err := json.Unmarshal([]byte(j), &data)
if err != nil {
panic(err)
}
// printing it out to show you it marshaled
// b, _ := json.MarshalIndent(data, "", " ")
// fmt.Println(string(b))
//
var myMovies []Movies
for _, d := range data {
temp := Movies{}
converting := d.([]interface{})
for _, movie := range converting {
convertingMovie := movie.(map[string]interface{})
temp.Length = convertingMovie["length"].(float64)
temp.ID = convertingMovie["ID"].(float64)
temp.ReleaseDate = convertingMovie["relaseDate"].(string)
// getting rid of these keys so the for loop below doesn't iterate on them
// need the for loop cuz I don't know what the key name is
delete(convertingMovie, "length")
delete(convertingMovie, "ID")
delete(convertingMovie, "relaseDate")
for key, val := range convertingMovie {
temp.Name = key
actors := val.(map[string]interface{})
temp.Actors = actors["actors"].([]interface{})
}
}
myMovies = append(myMovies, temp)
}
b, _ := json.MarshalIndent(myMovies, "", " ")
fmt.Println(string(b))
}
Probably a better way to do it above, but I provided a quick example. The best way would be to organize the json data better so that it fits into a struct better, otherwise the use reflection. Without to much more work, I'd use the for loop above, and add it to a struct in a may that makes sense to me and so that it can access the data easier. Consider above the start of the JSON parser, so now that you can access the json data, fit it into a struct then, change data around.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论