接受在解组 JSON 时动态键的 proto 结构

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

Accept dynamic keys in proto struct when unmarshalling JSON

问题

我的Proto文件大致如下:

    message Test {
        Service services = 1;
    }
    
    message Service {
        map<string, ServiceData> services = 1;
    }
    
    message ServiceData {
        string command = 1;
        string root = 2;
    }

这个.proto文件可以支持以下这样的JSON结构:

    {
        "services": {
            "service1": {
                "command": "command1",
                "root": "/"
            },
            "service2": {
                "command": "command2",
                "root": "/"
            }
        }
    }

现在,我想要读取test.json文件并进行解组:

    var test Test
    err := json.Unmarshal([]byte(file), &test)

为了成功解组这个JSON,你需要对.proto文件进行以下更改:

    message Test {
        map<string, ServiceData> services = 1;
    }
    
    message ServiceData {
        string command = 1;
        string root = 2;
    }

这样,你就可以成功解组这个JSON了。

英文:

My Proto file looks something like this:

    message Test {
        Service services = 1;
    }
    
    message Service {
        string command = 1;
        string root = 2;
    }

This .proto can support a json like this:

    {
            &quot;services&quot;: {   
                &quot;command&quot;: &quot;command2&quot;,
                &quot;root&quot;: &quot;/&quot; 
            },
    }

But, I want to manage a json that looks like this:

       {
                &quot;services&quot;: {
                        &quot;service1&quot;: {
                            &quot;command&quot;: &quot;command1&quot;,
                            &quot;root&quot;: &quot;/&quot;
                        },
                        &quot;service2&quot;: {
                            &quot;command&quot;: &quot;command2&quot;,
                            &quot;root&quot;: &quot;/&quot;
                        },
                },
        }

So, here all the services will have common structure but the key name will vary (i.e. &quot;service1&quot;, &quot;service2&quot;)

Now, I want to read the data from test.json and unmarshal it:

    var test *Test
    err := json.Unmarshal([]byte(file), &amp;test)

What changes should I do in the .proto so that I can unmarshall this json successfully?

答案1

得分: 2

使用 proto map

message Test {
    map<string, Service> services = 1;
}

message Service {
    string command = 1;
    string root = 2;
}

proto map 在 Go 中被编译为 map[K]V,所以在这种情况下是 map[string]*Service,这是建议的用于建模具有任意键的 JSON 的方式。

这将产生以下输出:

services:{key:"service1" value:{command:"command1" root:"/"}} services:{key:"service2" value:{command:"command2" root:"/"}}

示例程序:

package main

import (
	"encoding/json"
	"example.com/pb"
	"fmt"
)

const file = `{
            "services": {
                    "service1": {
                        "command": "command1",
                        "root": "/"
                    },
                    "service2": {
                        "command": "command2",
                        "root": "/"
                    }
            }
    }
`

func main() {
	test := &pb.Test{}
	err := json.Unmarshal([]byte(file), test)
	if err != nil {
		panic(err)
	}
	fmt.Println(test)
}
英文:

Use a proto map:

message Test {
    map&lt;string, Service&gt; services = 1;
}

message Service {
    string command = 1;
    string root = 2;
}

The proto map is compiled to map[K]V in Go, so map[string]*Service in this case, which is the recommended way to model JSON with arbitrary keys.

This will give the following output:

services:{key:&quot;service1&quot; value:{command:&quot;command1&quot; root:&quot;/&quot;}} services:{key:&quot;service2&quot; value:{command:&quot;command2&quot; root:&quot;/&quot;}}

Example program:

package main

import (
	&quot;encoding/json&quot;
	&quot;example.com/pb&quot;
	&quot;fmt&quot;
)

const file = `{
            &quot;services&quot;: {
                    &quot;service1&quot;: {
                        &quot;command&quot;: &quot;command1&quot;,
                        &quot;root&quot;: &quot;/&quot;
                    },
                    &quot;service2&quot;: {
                        &quot;command&quot;: &quot;command2&quot;,
                        &quot;root&quot;: &quot;/&quot;
                    }
            }
    }
`


func main() {
	test := &amp;pb.Test{}
	err := json.Unmarshal([]byte(file), test)
	if err != nil {
		panic(err)
	}
	fmt.Println(test)
}

huangapple
  • 本文由 发表于 2021年11月24日 15:29:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/70092138.html
匿名

发表评论

匿名网友

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

确定