[英]create a map of string from a JSON with unknow key-values in Go
I try to create a map of strings from a JSON with an undefined number of unknow key-values. 我尝试使用未定义数量的未知键值从JSON创建字符串映射。
Here is my example JSON file: 这是我的示例JSON文件:
{
"localhost":
{
"tag": "dev_latest",
"vhost": "localhost.com"
},
"development":
{
"tag": "dev_latest",
"vhost": "dev.com"
}
}
I want to create a map[string]string
with value like this: 我想创建一个
map[string]string
,其值如下:
config := map[string]string{
"localhost-tag": "dev_latest",
"localhost-vhost": "localhost.com,
"development-tag": "dev_latest,
...
}
To parse a JSON with "github.com/jmoiron/jsonq"
with known values, is quite easy, but in this case, localhost
can be anything and tag
can be any other thing. 用已知值的
"github.com/jmoiron/jsonq"
解析JSON是很容易的,但是在这种情况下, localhost
可以是任何东西,而tag
可以是任何其他东西。
My entry point in my Go code is like this: 我在Go代码中的入口点是这样的:
func ParseJson(){
configPath := GetConfigPath()
b, err := ioutil.ReadFile(configPath)
// Here, I need to create my map of strings..
return configKeyStr
}
Any help will be really appreciate. 任何帮助将不胜感激。
Thanks! 谢谢!
Easy to do. 容易做。 Simply convert.
简单地转换。
package main
import (
"encoding/json"
"fmt"
"log"
)
const s = `
{
"localhost":
{
"tag": "dev_latest",
"vhost": "localhost.com"
},
"development":
{
"tag": "dev_latest",
"vhost": "dev.com"
}
}
`
func main() {
var m map[string]interface{}
err := json.Unmarshal([]byte(s), &m)
if err != nil {
log.Fatal(err)
}
mm := make(map[string]string)
for k, v := range m {
mm[k] = fmt.Sprint(v)
}
fmt.Println(mm)
}
Wrote flatten (maybe works as charm) 写扁平化(也许可以作为魅力)
package main
import (
"encoding/json"
"fmt"
"log"
"reflect"
)
const s = `
{
"localhost":
{
"tag": "dev_latest",
"vhost": "localhost.com"
},
"development":
{
"tag": "dev_latest",
"vhost": "dev.com"
}
}
`
func flatten(m map[string]interface{}) map[string]string {
mm := make(map[string]string)
for k, v := range m {
switch reflect.TypeOf(v).Kind() {
case reflect.Map:
mv := flatten(v.(map[string]interface{}))
for kk, vv := range mv {
mm[k+"-"+kk] = vv
}
case reflect.Array, reflect.Slice:
for kk, vv := range m {
if reflect.TypeOf(vv).Kind() == reflect.Map {
mv := flatten(vv.(map[string]interface{}))
for kkk, vvv := range mv {
mm[k+"-"+kkk] = vvv
}
} else {
mm[k+"-"+kk] = fmt.Sprint(vv)
}
}
default:
mm[k] = fmt.Sprint(v)
}
}
return mm
}
func main() {
var m map[string]interface{}
err := json.Unmarshal([]byte(s), &m)
if err != nil {
log.Fatal(err)
}
b, _ := json.MarshalIndent(flatten(m), "", " ")
println(string(b))
}
You can't have this automatically, but you can range over the "internal" maps, and combine the outer keys with the inner keys using simple string concatenation ( +
operator). 您不能自动使用此功能,但是可以在“内部”映射上进行调整,并使用简单的字符串连接(
+
运算符)将外部键与内部键组合在一起。 Also it's recommended to unmarshal directly into a value of map[string]map[string]string
so you don't need to use type assertions. 另外,建议直接解组为
map[string]map[string]string
的值,这样就不必使用类型断言。 Also no need to use any external libraries for this, the standard encoding/json
package is perfectly enough for this. 同样,也不需要为此使用任何外部库,为此,标准的
encoding/json
包就足够了。
Example: 例:
var mm map[string]map[string]string
if err := json.Unmarshal([]byte(src), &mm); err != nil {
panic(err)
}
config := map[string]string{}
for mk, m := range mm {
for k, v := range m {
config[mk+"-"+k] = v
}
}
fmt.Println(config)
Output is as expected (try it on the Go Playground ): 输出是预期的(在Go Playground上尝试):
map[localhost-tag:dev_latest localhost-vhost:localhost.com
development-tag:dev_latest development-vhost:dev.com]
Since in the question you mentioned undefined number of unknown key-values , you may need to deal with JSON document with unknown number of nesting level and having a value other than string
. 由于在问题中您提到了不确定数量的未知键值 ,因此您可能需要处理嵌套数量未知且具有
string
以外的值的JSON文档。 In this case, you need to Unmarshal
json to map[string]interface{}
, then use recursion to make flat map. 在这种情况下,您需要
Unmarshal
json到map[string]interface{}
,然后使用递归制作平面地图。 Once the json document unmrashaled to map[string]interface{}
, use the following function: 将json文档完整地
map[string]interface{}
到map[string]interface{}
,请使用以下功能:
func flatMap(src map[string]interface{}, baseKey, sep string, dest map[string]string) {
for key, val := range src {
if len(baseKey) != 0 {
key = baseKey + sep + key
}
switch val := val.(type) {
case map[string]interface{}:
flatMap(val, key, sep, dest)
case string:
dest[key] = val
case fmt.Stringer:
dest[key] = val.String()
default:
//TODO: You may need to handle ARRAY/SLICE
//simply convert to string using `Sprintf`
//NOTE: modify as needed.
dest[key] = fmt.Sprintf("%v", val)
}
}
}
The working solution adapted from mattn answer at https://play.golang.org/p/9SQsbAUFdY 工作解决方案改编自https://play.golang.org/p/9SQsbAUFdY上的 mattn答案
As pointed by mattn, you may have problem when you want to writeback the configuration value. 正如mattn指出的那样,当您想回写配置值时可能会遇到问题。 In that case, use the existing library/framework.
在这种情况下,请使用现有的库/框架。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.