在Go中合并动态数据结构 [英] Merge a dynamic data structure in Go
问题描述
我有这个新来的有效载荷,我不能改变。
{
source:一些随机源码,
table:hosts_table ,
data:[
[address,id,services_with_info],
[0.0.0.1,1111,[
[service_3 ,非常酷,1],
[service_4,非常酷,2]
]
],
[0.0.0.2,2222 ,[
[service_3,非常酷,3],
[service_4,非常酷,4]
]
]
]}
我需要获取data的第一个索引并创建一个新的JSON对象,看起来像这样...
$ b $ pre $ data:[{
address:0.0.0.1 ,
id:1111,
services_with_info:[
{
service_name:service_1,
service_message:非常酷 ,
service_id:1
},
{...}
]},
{...}]
,然后用它建立一个 [] Host
的数据st结构是5K主机长。我能够将其映射到一个结构,但需要首先将其转换为此格式。我了解如何解组JSON,但前提是我可以将有效负载转换为上述内容。
我不确定我是否理解您的要求。
<可能是这样的一些事情?
可能需要一些工作,比如对结构指向一些指针,而不是一堆结构来防止分配和复制,错误处理,更多的定制逻辑来转换值,匿名化/封装转换过程中使用的私有结构,添加json标签到这些结构等。
我在IncomingPaylod上为数据创建自定义的Unmarshaller字段:解析期望的数据,将其转换为[] MyData并用它更新数据字段。
我为expected_data和expected_services_with_info创建了自定义Unmarshallers,因为我们期望它作为值的数组(3个值:字符串,int和[数组字符串,int(?),int ]),但我想将它转换为漂亮的结构。如果你不喜欢它,你可以删除它,将预期数据解组为[] interface {},并使用它[] interface {} {string,int,[] interface {} {string,int,int}}。容易得到它错误,所以我更喜欢结构,更容易阅读和维护和重构(我认为你的应用程序中有更多的领域)。
$ b
https://play.golang.org/p/xHTvyhecra
package main
import(
encoding / json
fmt
strconv
类型IncomingPayload结构{
源字符串`json:源``
表字符串`json:table`
Data MyDataSlice`json: data`
}
类型MyDataSlice [] MyData
类型MyData结构{
地址字符串`json:地址``
ID字符串` json:id`
Services_with_info [] MyServiceWithInfo`json:services_with_info`
}
type MyServiceWithInfo struct {
ServiceName string`json:service_name `
ServiceMessage字符串`json:service_message`
ServiceID int`json:service_id`
}
类型expected_data struct {
IP字符串
ID int
Info [] expected_services_with_info
}
类型expected_services_with_info结构{
名称字符串
描述字符串
ID int
}
func(ed * expected_data)UnmarshalJSON (buf [] byte)error {
tmp:= [] interface {} {& ed.IP,& ed.ID,& ed.Info}
//转换[address ,id,services_with_info]转换为struct
//将使用* expected_services_with_info解析services_with_info(ed.Info).UnmarshalJSON
json.Unmarshal(buf,& tmp)
返回nil
}
func(es * expected_services_with_info)UnmarshalJSON(buf [] byte)error {
tmp:= [] interface {} {& es.Name, & es.Desc,& es.ID}
//将[service_3,非常酷,1]转换为struct
json.Unmarshal(buf,& tmp)
返回零
}
func(md * MyDataSlice)Unm arshalJSON(p [] byte)错误{
var incoming_data_slice [] expected_data
json.Unmarshal(p,&incoming_data_slice)
//fmt.Println(\"incoming,incoming_data_slice)
//将incoming_data_slice转换为您的需要使用您的数据类型
for i:=范围incoming_data_slice {
my_data:= MyData {
Address:incoming_data_slice [i] .IP, //复制
ID:strconv.Itoa(incoming_data_slice [i] .ID),//一些转换
// nil slice完全没问题,但是如果你愿意,你可以做
//数据:make(MyDataSlice,len(incoming_data_slice)),
}
//不知道最好是什么:i:= range data或_,v :=范围数据(第二个副本?并导致分配)
for j:=范围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)
}
//并填充
* md = append(* md,my_data)
}
返回零
$ b func main(){
test_json:=`{
source:一些随机源码,
table:hosts_table,
data:[
[address,id,services_with_info],
[0.0.0.1,1111,[
[service_3,非常酷,1],
[service_4,非常酷,2]
]
],
[ 0.0.0.2,2222,[
[service_3,非常酷,3],
[service_4,非常酷,4]
]
]
]}`
var payload IncomingPayload
json.Unmarshal ([] byte(test_json),& payload)
fmt.Println(payload,payload)
buf,_:= json.MarshalIndent(payload,,\\ \\ t)
fmt.Println(string(buf))
}
I have this incoming payload, that I cannot change.
{
"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]
]
]
]}
i need to take the first index of "data" and create a new JSON object, that looks like this...
"data": [{
"address": "0.0.0.1",
"id": 1111,
"services_with_info":[
{
"service_name": "service_1",
"service_message": "is very cool",
"service_id": 1
},
{...}
]},
{...}]
and then build an []Host
's from it the data structure is 5k "hosts" long. I was able to map this to a struct, but need to get it into this format first. I understand how to unmarshal the JSON, but only if I can convert the payload to the above.
I'm not sure if I understood what you wants.
May be some thing like this? Probably it needs some work, like make slice of pointers to structs instead of slice of structs to prevent allocation and copy, error handling, more custom logic to convert values, anonymize/incapsulate private structs used in the middle of conversion, add json tags to those structures etc.
I create custom Unmarshaller for Data field on IncomingPaylod: parsing expected data, converting it to []MyData and updating Data field with it.
I created custom Unmarshallers for expected_data and expected_services_with_info because we expect it as array of values (3 values: string, int and [array of string, int(?), int]), but I want to convert it to nice structs. If you dont like it, you can delete it, Unmarshal expected data to []interface{} and work with it like []interface{}{string, int, []interface{}{string, int, int} }. Easy to get it wrong, so i like structs more, its easier to read and maintain and refactor (i think there are more fields in you app).
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))
}
这篇关于在Go中合并动态数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!