我有这个传入的有效载荷,我无法改变。
{
"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" hosts"长。我能够将它映射到一个结构,但需要先将它转换为这种格式。我理解如何解组JSON,但前提是我可以将有效负载转换为上述内容。
答案 0 :(得分:3)
您可以使用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"
。
答案 1 :(得分:2)
我不确定我是否理解你想要的东西。
可能是这样的事情? 可能它需要一些工作,比如制作指向结构的指针切片而不是结构切片以防止分配和复制,错误处理,转换值的更多自定义逻辑,匿名/封装在转换过程中使用的私有结构,添加json标记到那些结构等。
我在IncomingPaylod上为数据字段创建自定义Unmarshaller:解析预期数据,将其转换为[] MyData并用它更新数据字段。
我为expected_data和expected_services_with_info创建了自定义Unmarshallers,因为我们期望它作为值数组(3个值:string,int和[array of string,int(?),int]),但我想将它转换为nice structs 。如果你不喜欢它,你可以删除它,将预期的数据解组到[] 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))
}