为了账号安全,请及时绑定邮箱和手机立即绑定

JSON 字符串的交集

JSON 字符串的交集

Go
噜噜哒 2023-04-17 16:46:28
我试图找到一种方法来使用一个 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 []stringnodenames = append(nodenames, traverseJSON("", result)...)然后我打算编写第二个函数,它使用节点名称的这一部分从输入的 JSON 字符串构造一个 JSON 字符串,但我失去了动力,开始认为我可能走错了路。对此的任何帮助将不胜感激。
查看完整描述

1 回答

?
函数式编程

TA贡献1807条经验 获得超9个赞

只需创建一个基于模板和源地图“克隆”地图的功能。

该解决方案将遍历模板映射的条目,并为每一(k, v)对在目标映射中生成一个条目,如下所示:

  • 如果不是映射,只需从源映射中v获取键的值,并在目标中使用它。k

  • 如果v也是一个地图,则递归地调用此“克隆器”,新模板地图是v,新源是键的源的值kk此递归调用的结果将是目标映射中键的值。

这就是它的样子:

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

}

就这样。


测试它:


// 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)

}

使用示例 JSON 输出(在Go Playground上尝试):


{

  "id": "831",

  "options": {

    "leatherseats": "black",

    "sunroof": "full"

  }

}

笔记:


该解决方案假定源映射符合模板。也就是说,如果模板包含某个键的映射,则源映射也应包含相同键的映射。如果不能保证这一点,procMap()则应通过检查来扩展该函数以避免运行时恐慌,如下所示:


for k, v := range tmpl {

    if innerMap, ok := v.(map[string]interface{}); ok {

        if src2, ok2 := src[k].(map[string]interface{}); ok2 {

            dst[k] = procMap(innerMap, src2)

        } else {

            log.Printf("src is not conform to template at key %q", k)

        }

    } else {

        dst[k] = src[k]

    }

}

另请注意,JSON 数组(切片)不会以任何特殊方式处理,这意味着如果模板包含切片,则源中的值将按原样使用,如果切片包含映射,则不会发生递归。

查看完整回答
反对 回复 2023-04-17
  • 1 回答
  • 0 关注
  • 117 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信