Go中如何比较两个json?深度优先搜索解决,超详细代码!

本文介绍了在Go中如何深度比较两个JSON对象,详细解释了处理JSON结构、比较过程和注意事项,提供了一段实现优雅比较的代码示例,包括处理JSON、JSON数组和简单值的比较,并记录不同之处。
摘要由CSDN通过智能技术生成

假设,现在有两个简单的json文件。

{
   
    "id":1,
    "name":"testjson01",
    "isadmin":true
}
{
   
    "isadmin":true,
    "name":"testjson01",
    "id":1    
}

那么,如何比较这两个json的内容是否相同呢?

首先,最基本的方法就是利用golang的反射提供的DeepEqual()

假设我们有一个读取json文件的函数如下:

func LoadJson(path string, dist interface{
   }) (err error) {
   
    var content []byte
    if content, err = ioutil.ReadFile(path); err == nil {
   
        err = json.Unmarshal(content, dist)
    }
    return err
}

那么,我们可以调用该函数来读取json文件。由于json的结构是未知的,所以我们需要声明一个map[string]interface{}来存放对json文件的解析结果。

func main() {
   
    var (
        json1 map[string]interface{
   }
        json2 map[string]interface{
   }
    )
    if err := service.LoadJson("./etc/json/json01.json", &json1); err != nil {
   
        fmt.Println(err)
    }
    if err := service.LoadJson("./etc/json/json02.json", &json2); err != nil {
   
        fmt.Println(err)
    }
    fmt.Println(reflect.DeepEqual(json1, json2))
}

这会在终端中输出一个比较的结果:

true

如果我们只需要知道两个json是否相同,那么这样一段简单的代码就可以实现这个要求。

接下来,我们要解决“优雅的”这个定语。

大多数情况下,我们比较两个json,不止需要知道他们是否相同。在他们结构不同的时候,我们还会很自然的关心,他们的区别在哪里。

下面就来解决这个问题。

首先,我们来分析一下json的结构。json作为一个类map的结构体,他的value可能分为3类:

  1. json。json的值可能还是json。这就意味着,遇到了值为json的情况,我们需要进行嵌套的比较。另外一点需要注意的,是json结构体本身是无序的,所以比较过程中,要处理好这一点。

  2. jsonArray。json的值也有可能是jsonArray。这不仅带来了嵌套比较,还要注意,jsonArray跟json相比,它是有序的。

  3. 简单值。这里的简单值包括字符串,实数和布尔值。简单值只需要比较类型和值是否相同即可,也不存在嵌套的情况。

那么思路就清晰了,对于两个json结构体json1和json2,我们首先要遍历json1的键值对,检查json2是否存在对应的键值对,然后根据值的类型分别进行处理。

这里,我们利用golang的反射value.(type)。需要注意的是,value.(type)只能用在switch-case结构中,当我们通过switch判断了value的类型之后,就可以利用断言对其进行类型转换。

在简单值的比较中,因为其不存在结构嵌套的情况,值不同即说明该处存在不同,这样我们就可以用DeepEqual()来简化比较过程。

最后再检查json2中是否存在json1不存在的键值对。

这样,比较是否相同这一目的就达到了。但是目前,这与DeepEqual()并没有不同。所以,我们还需要把整个比较的过程记录下来。对于相同的部分,我们记录json的内容;对于不同的部分,我们分别记录下两者的区别。

[复制代码](javascript:void(0)😉

type JsonDiff struct {
   
    HasDiff bool
    Result  string
}

func marshal(j interface{
   }) string {
   
    value, _ := json.Marshal(j)
    return string(value)
}

func jsonDiffDict(json1, json2 map[string]interface{
   }, depth int, diff *JsonDiff) {
   
    blank := strings.Repeat(" ", (2 * (depth - 1)))
    longBlank := strings.Repeat(" ", (2 * (depth)))
    diff.Result = diff.Result + "\n" + blank + "{"
    for key, value := range json1 {
   
        quotedKey := fmt.Sprintf("\"%s\"", key)
        if _, ok := json2[key]; ok {
   
            switch value.(type) {
   
            case map[string]interface{
   }:
                if _, ok2 := json2[key].(map[string]interface{
   }); !ok2 {
   
                    diff.HasDiff = true
                    diff.Result = diff.Result + "\n-" + blank + quotedKey + ": " + marshal(value) + ","
                    diff.Result = diff.Result + "\n+" + blank + quotedKey + ": " + marshal(json2[key])
                } else {
   
                    diff.Result = diff.Result + "\n" + longBlank + quotedKey + ": "
                    jsonDiffDict(value.(map[string]interface{
   }), json2[key].(map[string]interface{
   }), depth+1, diff)
                }
            case []interface{
   }:
                diff.Result = diff.Result + "\n" + longBlank + quotedKey + ": "
                if _, ok2 := json2[key].([]interface{
   }); !ok2 {
   
                    diff.HasDiff = true
                    diff.Result = diff.Result + "\n-" + blank + quotedKey + ": " + marshal(value) + ","
     
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值