如何在Go中将嵌套的JSON解组为结构体,如果外部元素不相同

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

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

{
&quot;movies&quot;: [
    {
        &quot;movie_title_A&quot;: {
            &quot;actors&quot;: [
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;....&quot;
            ]
        },
        &quot;ID&quot;: 99992,
        &quot;length&quot;: 120,
        &quot;relaseDate&quot;: &quot;2.10.2012&quot;
    },
    {
        &quot;movie_title_B&quot;: {
            &quot;actors&quot;: [
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;&quot;,
                &quot;&lt;actorID1123123&gt;....&quot;
            ]
        },
        &quot;ID&quot;: 123124,
        &quot;length&quot;: 90,
        &quot;relaseDate&quot;: &quot;10.10.2012&quot;
    }
]
}

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 (
&quot;encoding/json&quot;
&quot;fmt&quot;
)
const j = `{
&quot;movies&quot;: [
{
&quot;asd123&quot;: {
&quot;actors&quot;: [
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;
]
},
&quot;ID&quot;: 99992,
&quot;length&quot;: 120,
&quot;relaseDate&quot;: &quot;2.10.2012&quot;
},
{
&quot;2movie23123&quot;: {
&quot;actors&quot;: [
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;,
&quot;&lt;actorID1123123&gt;&quot;
]
},
&quot;ID&quot;: 123124,
&quot;length&quot;: 90,
&quot;relaseDate&quot;: &quot;10.10.2012&quot;
}
]
}`
// 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), &amp;data)
if err != nil {
panic(err)
}
// printing it out to show you it marshaled
// b, _ := json.MarshalIndent(data, &quot;&quot;, &quot; &quot;)
// 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[&quot;length&quot;].(float64)
temp.ID = convertingMovie[&quot;ID&quot;].(float64)
temp.ReleaseDate = convertingMovie[&quot;relaseDate&quot;].(string)
// getting rid of these keys so the for loop below doesn&#39;t iterate on them
// need the for loop cuz I don&#39;t know what the key name is
delete(convertingMovie, &quot;length&quot;)
delete(convertingMovie, &quot;ID&quot;)
delete(convertingMovie, &quot;relaseDate&quot;)
for key, val := range convertingMovie {
temp.Name = key
actors := val.(map[string]interface{})
temp.Actors = actors[&quot;actors&quot;].([]interface{})
}
}
myMovies = append(myMovies, temp)
}
b, _ := json.MarshalIndent(myMovies, &quot;&quot;, &quot; &quot;)
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.

huangapple
  • 本文由 发表于 2017年3月29日 02:21:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/43077124.html
匿名

发表评论

匿名网友

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

确定