在 Go 中合并动态数据结构

我有这个传入的有效负载,我无法更改。


{

"source": "some random source",

"table": "hosts_table",

"data": [

    ["address", "id", "services_with_info"],

    ["0.0.0.1", 1111, [

            ["service_3", "is very cool", 1],

            ["service_4", "is very cool", 2]

        ]

    ],

    ["0.0.0.2", 2222, [

            ["service_3", "is very cool", 3],

            ["service_4", "is very cool", 4]

        ]

    ]

]}

我需要获取“数据”的第一个索引并创建一个新的 JSON 对象,看起来像这样......


"data": [{

"address": "0.0.0.1", 

"id": 1111, 

"services_with_info":[

    {

        "service_name": "service_1", 

        "service_message": "is very cool", 

        "service_id": 1

    }, 

    {...}

]}, 

{...}]

然后[]Host从中构建一个 's 数据结构是 5k“主机”长。我能够将其映射到结构,但需要先将其转换为这种格式。我了解如何解组 JSON,但前提是我可以将有效负载转换为上述内容。


跃然一笑
浏览 308回答 2
2回答

梵蒂冈之花

您可以为此使用 json.Unmarshal 并根据您的条件解析数据。我只是这样做"data",你也可以这样做"services_with_info"b := []byte(`{            "source": "some random source",            "table": "hosts_table",            "data": [                ["address", "id", "services_with_info"],                ["0.0.0.1", 1111, [                        ["service_3", "is very cool", 1],                        ["service_4", "is very cool", 2]                    ]                ],                ["0.0.0.2", 2222, [                        ["service_3", "is very cool", 3],                        ["service_4", "is very cool", 4]                    ]                ]            ]}`)var f interface{}err := json.Unmarshal(b, &f)if err != nil {    fmt.Println(err)    return}m := f.(map[string]interface{})result := make(map[string]interface{})results := make(map[string][]map[string]interface{})for k, v := range m {    if k == "data" {        s := v.([]interface{})        header := make([]interface{}, 3)        for i, u := range s {            if i == 0 {                header = u.([]interface{})            } else {                row := u.([]interface{})                for j, k := range header {                    result[k.(string)] = row[j]                }                results["data"] = append(results["data"], result)            }        }    }}fmt.Println(results)这里"results"是"data"根据需要。

杨__羊羊

我不确定我是否明白你想要什么。可能是这样的事情?可能它需要一些工作,比如制作指向结构的指针切片而不是结构切片以防止分配和复制,错误处理,更多自定义逻辑来转换值,匿名/封装转换过程中使用的私有结构,添加 json 标记那些结构等我为 IncomingPaylod 上的 Data 字段创建自定义 Unmarshaller:解析预期数据,将其转换为 []MyData 并使用它更新 Data 字段。我为 expected_data 和 expected_services_with_info 创建了自定义解组器,因为我们期望它作为值数组(3 个值:字符串、整数和 [字符串数组、int(?)、int]),但我想将其转换为漂亮的结构。如果您不喜欢它,可以将其删除,将预期数据解组到 []interface{} 并像 []interface{}{string, int, []interface{}{string, int, int} } 一样使用它。容易出错,所以我更喜欢结构,它更容易阅读、维护和重构(我认为你的应用程序中有更多字段)。https://play.golang.org/p/xHTvyhecrapackage mainimport (    "encoding/json"    "fmt"    "strconv")type IncomingPayload struct {    Source string      `json:"source"`    Table  string      `json:"table"`    Data   MyDataSlice `json:"data"`}type MyDataSlice []MyDatatype MyData struct {    Address            string              `json:"address"`    ID                 string              `json:"id"`    Services_with_info []MyServiceWithInfo `json:"services_with_info"`}type MyServiceWithInfo struct {    ServiceName    string `json:"service_name"`    ServiceMessage string `json:"service_message"`    ServiceID      int    `json:"service_id"`}type expected_data struct {    IP   string    ID   int    Info []expected_services_with_info}type expected_services_with_info struct {    Name string    Desc string    ID   int}func (ed *expected_data) UnmarshalJSON(buf []byte) error {    tmp := []interface{}{&ed.IP, &ed.ID, &ed.Info}    // converts ["address", "id", "services_with_info"] into a struct    // will unmarshall "services_with_info" (ed.Info) with *expected_services_with_info.UnmarshalJSON    json.Unmarshal(buf, &tmp)    return nil}func (es *expected_services_with_info) UnmarshalJSON(buf []byte) error {    tmp := []interface{}{&es.Name, &es.Desc, &es.ID}    // converts ["service_3", "is very cool", 1] into a struct    json.Unmarshal(buf, &tmp)    return nil}func (md *MyDataSlice) UnmarshalJSON(p []byte) error {    var incoming_data_slice []expected_data    json.Unmarshal(p, &incoming_data_slice)    //fmt.Println("incoming", incoming_data_slice)    //transform incoming_data_slice to your needs using your data type    for i := range incoming_data_slice {        my_data := MyData{            Address: incoming_data_slice[i].IP,               //copy            ID:      strconv.Itoa(incoming_data_slice[i].ID), //some transformation            //nil slice is totally fine, but if you wish you can do            //Data: make(MyDataSlice, len(incoming_data_slice)),        }        //not sure what would be best: "i := range data" or "_, v := range data" (second one makes a copy? and causes allocation)        for j := range incoming_data_slice[i].Info {            tmp := MyServiceWithInfo{                ServiceName: incoming_data_slice[i].Info[j].Name,                ServiceMessage: incoming_data_slice[i].Info[j].Desc,                ServiceID: incoming_data_slice[i].Info[j].ID,            }            my_data.Services_with_info = append(my_data.Services_with_info, tmp)        }        //and populate        *md = append(*md, my_data)    }    return nil}func main() {    test_json := `{"source": "some random source","table": "hosts_table","data": [    ["address", "id", "services_with_info"],    ["0.0.0.1", 1111, [            ["service_3", "is very cool", 1],            ["service_4", "is very cool", 2]        ]    ],    ["0.0.0.2", 2222, [            ["service_3", "is very cool", 3],            ["service_4", "is very cool", 4]        ]    ]]}`    var payload IncomingPayload    json.Unmarshal([]byte(test_json), &payload)    fmt.Println("payload", payload)    buf, _ := json.MarshalIndent(payload, "", "\t")    fmt.Println(string(buf))}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go