【问题标题】:How to find the difference/mismatch between two JSON file?如何找到两个 JSON 文件之间的差异/不匹配?
【发布时间】:2018-05-20 06:01:21
【问题描述】:

我有两个 json 文件,一个是预期的 json,另一个是 GET API 调用的结果。我需要比较并找出文件中的不匹配。

预期的 Json:

{
  "array": [
    1,
    2,
    3
  ],
  "boolean": true,
  "null": null,
  "number": 123,
  "object": {
    "a": "b",
    "c": "d",
    "e": "f"
  },
  "string": "Hello World"
}

实际的 Json 响应:

{
  "array": [
    1,
    2,
    3
  ],
  "boolean": true,
  "null": null,
  "number": 456,
  "object": {
    "a": "b",
    "c": "d",
    "e": "f"
  },
  "string": "India"
}

实际上有两个不匹配:收到的号码是456,字符串是印度。

有没有办法比较这两个不匹配的结果。

这需要在 gatling/scala 中实现。

【问题讨论】:

    标签: json scala gatling


    【解决方案1】:

    使用 diffson - RFC-6901 和 RFC-6902 的 Scala 实现:https://github.com/gnieh/diffson

    【讨论】:

      【解决方案2】:

      json4s 有一个方便的 diff 函数,此处描述:https://github.com/json4s/json4s(搜索 Merging & Diffing)和 API 文档:https://static.javadoc.io/org.json4s/json4s-core_2.9.1/3.0.0/org/json4s/Diff.html

      【讨论】:

        【解决方案3】:

        例如,您可以使用 play-json library 并递归遍历这两个 JSON。对于下一个输入(比您的输入更复杂):

        左:

        {
          "array" : [ 1, 2, 4 ],
          "boolean" : true,
          "null" : null,
          "number" : 123,
          "object" : {
            "a" : "b",
            "c" : "d",
            "e" : "f"
          },
          "string" : "Hello World",
          "absent-in-right" : true,
          "different-types" : 123
        }
        

        右:

        {
          "array" : [ 1, 2, 3 ],
          "boolean" : true,
          "null" : null,
          "number" : 456,
          "object" : {
            "a" : "b",
            "c" : "d",
            "e" : "ff"
          },
          "string" : "India",
          "absent-in-left" : true,
          "different-types" : "YES"
        }
        

        它产生这个输出:

        Next fields are absent in LEFT: 
             *\absent-in-left
        Next fields are absent in RIGHT: 
             *\absent-in-right
        '*\array\(2)' => 4 != 3
        '*\number' => 123 != 456
        '*\object\e' => f != ff
        '*\string' => Hello World != India
        Cannot compare JsNumber and JsString in '*\different-types'
        

        代码:

        val left = Json.parse("""{"array":[1,2,4],"boolean":true,"null":null,"number":123,"object":{"a":"b","c":"d","e":"f"},"string":"Hello World","absent-in-right":true,"different-types":123}""").asInstanceOf[JsObject]
        val right = Json.parse("""{"array":[1,2,3],"boolean":true,"null":null,"number":456,"object":{"a":"b","c":"d","e":"ff"},"string":"India","absent-in-left":true,"different-types":"YES"}""").asInstanceOf[JsObject]
        
        // '*' - for the root node
        showJsDiff(left, right, "*", Seq.empty[String])
        
        def showJsDiff(left: JsValue, right: JsValue, parent: String, path: Seq[String]): Unit = {
          val newPath = path :+ parent
          if (left.getClass != right.getClass) {
            println(s"Cannot compare ${left.getClass.getSimpleName} and ${right.getClass.getSimpleName} " +
              s"in '${getPath(newPath)}'")
          }
          else {
            left match {
              // Primitive types are pretty easy to handle
              case JsNull => logIfNotEqual(JsNull, right.asInstanceOf[JsNull.type], newPath)
              case JsBoolean(value) => logIfNotEqual(value, right.asInstanceOf[JsBoolean].value, newPath)
              case JsNumber(value) => logIfNotEqual(value, right.asInstanceOf[JsNumber].value, newPath)
              case JsString(value) => logIfNotEqual(value, right.asInstanceOf[JsString].value, newPath)
              case JsArray(value) =>
                // For array we have to call showJsDiff on each element of array
                val arr1 = value
                val arr2 = right.asInstanceOf[JsArray].value
                if (arr1.length != arr2.length) {
                  println(s"Arrays in '${getPath(newPath)}' have different length. ${arr1.length} != ${arr2.length}")
                }
                else {
                  arr1.indices.foreach { idx =>
                    showJsDiff(arr1(idx), arr2(idx), s"($idx)", newPath)
                  }
                }
              case JsObject(value) =>
                val leftFields = value.keys.toSeq
                val rightJsObject = right.asInstanceOf[JsObject]
                val rightFields = rightJsObject.fields.map { case (name, value) => name }
        
                val absentInLeft = rightFields.diff(leftFields)
                if (absentInLeft.nonEmpty) {
                  println("Next fields are absent in LEFT: ")
                  absentInLeft.foreach { fieldName =>
                    println(s"\t ${getPath(newPath :+ fieldName)}")
                  }
                }
                val absentInRight = leftFields.diff(rightFields)
                if (absentInRight.nonEmpty) {
                  println("Next fields are absent in RIGHT: ")
                  absentInRight.foreach { fieldName =>
                    println(s"\t ${getPath(newPath :+ fieldName)}")
                  }
                }
                // For common fields we have to call showJsDiff on them
                val commonFields = leftFields.intersect(rightFields)
                commonFields.foreach { field =>
                  showJsDiff(value(field), rightJsObject(field), field, newPath)
                }
        
            }
          }
        }
        
        
        def logIfNotEqual[T](left: T, right: T, path: Seq[String]): Unit = {
          if (left != right) {
            println(s"'${getPath(path)}' => $left != $right")
          }
        }
        
        def getPath(path: Seq[String]): String = path.mkString("\\")
        

        【讨论】:

          猜你喜欢
          • 2021-08-18
          • 1970-01-01
          • 1970-01-01
          • 2014-02-02
          • 1970-01-01
          • 1970-01-01
          • 2013-01-02
          • 2019-09-28
          • 1970-01-01
          相关资源
          最近更新 更多