Scala JSON diffs - PullRequest
       4

Scala JSON diffs

0 голосов
/ 10 марта 2020

У меня есть два JSON с одинаковыми ключами.

val json1 = 
"""{
  'name': 'Henry',
  'age' : 26,
  'activities' : {
                 'school': 'basketball club', 
                 'after-school': 'chess'
                 }
}"""

val json2 = 
"""{
  'name': 'David',
  'age' : 23,
  'activities' : {
                 'school': 'baseball club', 
                 'after-school': 'programming'
                 }
}"""

Мне бы хотелось, например, разницу между двумя JSON, например:

name = Henry, David
age = 23, 26
activities.school= basketball club, baseball club
activities.after-school=chess, programming

Это не ' Я должен следовать приведенному выше формату, но я хотел бы получить ключи и значения, которые отличаются.

Ответы [ 2 ]

1 голос
/ 10 марта 2020

Как уже было предложено @ dk14, вы можете использовать diffson librarry: https://github.com/gnieh/diffson - но структура JsonPatch, которую она предоставляет, может быть не очень удобна для вашего случая использования, поэтому ее можно преобразовать в другой, чтобы получить результат в нужном формате. Пожалуйста, посмотрите пример кода ниже:

import diffson.jsonpatch.{Add, JsonPatch, Remove, Replace}
  import diffson.jsonpointer.{Part, Pointer}
  import io.circe.Json

  // Model representing plain json diff at certain path, that can be rendered at more human readable format 
  case class JsonPathDiff(path: Pointer, left: Option[Json], right: Option[Json]) {
    def readableString: String = {
      val pathReadableString: String = {
        def partToString(part: Part): String = part.fold(identity, _.toString)
        path.parts.toList.map(partToString).mkString(".")
      }

      def jsonReadableValue(json: Option[Json]): String = json.map(_.toString()).getOrElse("")
      val leftValue = jsonReadableValue(left)
      val rightValue = jsonReadableValue(right)
      s"$pathReadableString = $leftValue , $rightValue"
    }
  }

  // Model representing overall difference between two JSON's
  case class JsonDiff(diff: List[JsonPathDiff]) {
    def readableString: String = diff.map(_.readableString).mkString("\n")
  }

  object JsonDiff {
    def fromPatch(patch: JsonPatch[Json]): JsonDiff = {
      val paths = patch.ops.collect {
        case Add(path, value) => JsonPathDiff(path, None, Some(value))
        case Remove(path, old) => JsonPathDiff(path, old, None)
        case Replace(path, value, old) => JsonPathDiff(path, old, Some(value))
      }
      JsonDiff(paths)
    }
  }



  def main(args: Array[String]): Unit = {
    import diffson._
    import diffson.circe._
    import diffson.jsonpatch._
    import diffson.jsonpatch.lcsdiff.remembering._
    import diffson.lcs._
    import io.circe._
    import io.circe.parser._

    val json1 =
      s"""{
        "name": "Henry",
        "age" : 26,
        "activities" : {
                       "school": "basketball club",
                       "after-school": "chess"
                       }
      }"""

    val json2 =
      s"""{
        "name": "David",
        "age" : 23,
        "activities" : {
                       "school": "baseball club",
                       "after-school": "programming"
                       }
      }"""

    implicit val lcs = new Patience[Json]

    val patch: Either[ParsingFailure, JsonPatch[Json]] =
      for {
        json1 <- parse(json1)
        json2 <- parse(json2)
      } yield diff(json1, json2)

    val jsonDiff = JsonDiff.fromPatch(patch.right.get) // Using `get` for sake of example, avoid in real production code
    println(jsonDiff.readableString)
  }

, который даст следующий результат:

activities.after-school = "chess" , "programming"
activities.school = "basketball club" , "baseball club"
age = 26 , 23
name = "Henry" , "David"

Надеюсь, это поможет!

1 голос
/ 10 марта 2020

Вы можете попробовать diffson, библиотеку на основе цирка: https://github.com/gnieh/diffson

Пример:

import diffson._
import diffson.lcs._
import diffson.circe._
import diffson.jsonpatch._
import diffson.jsonpatch.lcsdiff._

import io.circe._
import io.circe.parser._

import cats._
import cats.implicits._

implicit val lcs = new Patience[Json]

val json1 = parse("""{
                    |  "a": 1,
                    |  "b": true,
                    |  "c": ["test", "plop"]
                    |}""".stripMargin)

val json2 = parse("""{
                    |  "a": 6,
                    |  "c": ["test2", "plop"],
                    |  "d": false
                    |}""".stripMargin)

val patch =
  for {
    json1 <- json1
    json2 <- json2
  } yield diff(json1, json2)

Возвращает:

[{
  "op":"replace",
  "path":"/a",
  "value":6
},{
  "op":"remove",
  "path":"/b"
},{
  "op":"replace",
  "path":"/c/0",
  "value":"test2"
},{
  "op":"add",
  "path":"/d",
  "value":false
}]

По сути, вы можете объединить "добавить" значения раздела для вашей конкретной цели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...