我有传入的有效负载,无法更改。
{ "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从中构建一个,其数据结构的长度为5k个“主机”。我能够将其映射到结构,但需要首先将其转换为这种格式。我了解如何解组JSON,但前提是可以将有效负载转换为上述格式。
[]Host
我不确定我是否了解您的需求。
可能是这样的事情?可能需要做一些工作,例如使指向结构的指针切片而不是结构的切片以防止分配和复制,错误处理,更多自定义逻辑来转换值,匿名化/封装转换中间使用的私有结构,向其中添加json标签这些结构等
我在IncomingPaylod上为Data字段创建了自定义的Unmarshaller:解析期望的数据,将其转换为[] MyData并使用它更新Data字段。
我为Expected_data和Expected_services_with_info创建了自定义Unmarshallers,因为我们希望它作为值数组(3个值:字符串,整数和[字符串数组,整数(?),整数]),但是我想将其转换为漂亮的结构。如果您不喜欢它,可以将其删除,将所需的数据解组到[] interface {},并像[] interface {} {string,int,[] interface {} {string,int,int}}一样使用它。容易出错,因此我更喜欢结构,它更易于阅读,维护和重构(我认为您的应用程序中包含更多字段)。
https://play.golang.org/p/xHTvyhecra
package main import ( "encoding/json" "fmt" "strconv" ) type IncomingPayload struct { Source string `json:"source"` Table string `json:"table"` Data MyDataSlice `json:"data"` } type MyDataSlice []MyData type 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)) }