Изменение массива JSON в Scala с помощью circe

У меня есть строка JSON со следующим массивом:

{
"cars": {
    "Nissan": [
        {"model":"Sentra", "doors":4},
        {"model":"Maxima", "doors":4}
    ],
    "Ford": [
        {"model":"Taurus", "doors":4},
        {"model":"Escort", "doors":2}
    ]
}
}

Я хочу отредактировать новый бренд карты, используя circe в scala.
Вместо

"Nissan": [
        {"model":"Sentra", "doors":4},
        {"model":"Maxima", "doors":4},
    ]

Хотелось бы получить в результате:

"Nissan": [
        {"model":"Sentra", "doors":1000},
    ],

Спасибо.


person Doe    schedule 07.10.2018    source источник
comment
что ты пытался сделать до сих пор? откуда 1000?   -  person Sebastian Celestino    schedule 07.10.2018
comment
Я думаю, что проще всего было бы сначала декодировать строку json, выполнить все преобразования непосредственно в объектах scala и снова закодировать результат обратно в json.   -  person Florian Baierl    schedule 08.10.2018
comment
Помимо правильного вопроса, попробуйте прочитать документацию и попытаться решить вашу проблему, прежде чем переходить на StackOverflow. Как только вы дойдете до того, чтобы задать здесь вопрос, перечислите то, что вы изучили, и любые фрагменты кода, которые вы написали при этом, даже если они не работают. StackOverflow не пишет ваш код, он пытается помочь вам там, где вы застряли. Это не для того, чтобы вас раздражать, а для того, чтобы вы научились делать это самостоятельно.   -  person Markus Appel    schedule 08.10.2018


Ответы (1)


Сделано после прочтения руководства, сделайте то же самое в следующий раз!

Помимо того, что ваш JSON недействителен (запятая в конце объекта в массиве "Nissan"), он должен выглядеть примерно так:

import cats.syntax.either._
import io.circe._, io.circe.parser._

val json: String = """
{
"cars": {
    "Nissan": [
        {"model":"Sentra", "doors":4},
        {"model":"Maxima", "doors":4}
    ],
    "Ford": [
        {"model":"Taurus", "doors":4},
        {"model":"Escort", "doors":2}
    ]
}
}
"""

val newJson = parse(json).toOption
  .flatMap { doc =>
    doc.hcursor
      .downField("cars")
      .downField("Nissan")
      .withFocus(_ =>
          Json.arr(
            Json.fromFields(
              Seq(
                ("model", Json.fromString("Sentra")),
                ("doors", Json.fromInt(1000))
              )
            )
          )
      )
      .top
  }

newJson match {
  case Some(v) => println(v.toString)
  case None => println("Failure!")
}

Попробуйте! (Повторите попытку, чтобы увидеть правильный отступ!)


newJson на самом деле Option, поэтому, если синтаксический анализ или изменение не удастся, вы получите None.

Вызов toOption на parse(json) преобразует возвращенный Either[Json] (синтаксический анализ выполнен / не удалось) в Option[Json].

В первую очередь нам нужно использовать Option[Json], потому что .top также возвращает Option[Json] (изменение выполнено / не удалось).

Таким образом, мы можем flatMap и не иметь дела с вложенными типами (см. здесь).

person Markus Appel    schedule 08.10.2018