我正在尝试找到一种方法来将一个JSON字符串用作某种“模板”,以应用于另一个JSON字符串。例如,如果我的模板如下所示:
{
"id": "1",
"options": {
"leatherseats": "1",
"sunroof": "1"
}
}
然后将其应用于以下JSON字符串:
{
"id": "831",
"serial": "19226715",
"options": {
"leatherseats": "black",
"sunroof": "full",
"fluxcapacitor": "yes"
}
}
我想要一个生成的JSON字符串,如下所示:
{
"id": "831",
"options": {
"leatherseats": "black",
"sunroof": "full",
}
}
不幸的是,我既不能依赖模板也不能依赖输入为固定格式,因此无法编组/解组为已定义的接口。
我写了一个遍历模板的递归函数,以构造一个带有要包含的每个节点名称的字符串切片。
func traverseJSON(key string, value interface{}) []string {
var retval []string
unboxed, ok := value.(map[string]interface{})
if ok {
for newkey, newvalue := range unboxed {
retval = append(retval, recurse(fmt.Sprintf("%s.%s", key, newkey), newvalue)...)
}
} else {
retval = append(retval, fmt.Sprintf("%s", key))
}
return retval
}
我将此函数称为如下:
template := `my JSON template here`
var result map[string]interface{}
json.Unmarshal([]byte(template), &result)
var nodenames []string
nodenames = append(nodenames, traverseJSON("", result)...)
然后我要编写第二个函数,该函数使用这部分节点名称从输入的JSON字符串构造JSON字符串,但用尽了精力,开始认为我可能还是走错了路。
任何帮助,将不胜感激。
答案 0 :(得分:4)
只需创建一个功能即可根据模板和源地图“克隆”地图。
该解决方案将遍历模板映射的条目,并为每个(k, v)
对在目标映射中生成一个条目,如下所示:
如果v
不是地图,只需从源地图获取k
键的值,然后在目标位置使用它即可。
如果v
也是一个映射,则递归调用此“克隆”,新模板映射为v
,新源为{{1 }}键。递归调用的结果将是目标映射中的k
键的值。
它是这样的:
k
仅此而已。
测试:
func procMap(tmpl, src map[string]interface{}) (dst map[string]interface{}) {
dst = map[string]interface{}{}
for k, v := range tmpl {
if innerMap, ok := v.(map[string]interface{}); ok {
dst[k] = procMap(innerMap, src[k].(map[string]interface{}))
} else {
dst[k] = src[k]
}
}
return dst
}
使用示例JSON输出(在Go Playground上尝试):
// tmpljson is the template JSON
var tmpl map[string]interface{}
if err := json.Unmarshal([]byte(tmpljson), &tmpl); err != nil {
panic(err)
}
// srcjson is the source JSON
var src map[string]interface{}
if err := json.Unmarshal([]byte(srcjson), &src); err != nil {
panic(err)
}
dst := procMap(tmpl, src)
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
if err := enc.Encode(dst); err != nil {
panic(err)
}
注释:
解决方案假定源映射符合模板。也就是说,如果模板包含某个键的映射,则源映射也应包含相同键的映射。如果不能保证这一点,请对{
"id": "831",
"options": {
"leatherseats": "black",
"sunroof": "full"
}
}
函数进行扩展检查,以避免运行时出现恐慌,如下所示:
procMap()
还请注意,JSON数组(切片)不会以任何特殊方式处理,这意味着如果模板包含切片,则按原样使用源中的值,并且如果切片包含地图,则不会进行递归。该解决方案也可以轻松扩展为处理切片,这是读者的练习。