Misalkan saya memiliki objek JSON seperti ini:

{
   "foo": true,
   "bar": {
      "baz": 1,
      "qux": {
        "msg": "hello world",
        "wow": [null]
      }
   }
}

Dan saya ingin meratakannya secara rekursif ke satu lapisan, dengan kunci digabung dengan garis bawah:

{
   "foo": true,
   "bar_baz": 1,
   "baz_qux_msg": "hello world",
   "baz_qux_wow": [null]
}

Bagaimana saya bisa melakukannya dengan Circe?

(Catatan: ini adalah FAQ lain dari saluran Circe Gitter.)

4
Travis Brown 20 September 2019, 13:04

1 menjawab

Jawaban Terbaik

Anda dapat melakukan ini tanpa terlalu banyak rasa sakit di Circe dengan metode rekursif:

import io.circe.Json

def flatten(combineKeys: (String, String) => String)(value: Json): Json = {
  def flattenToFields(value: Json): Option[Iterable[(String, Json)]] =
    value.asObject.map(
      _.toIterable.flatMap {
        case (k, v) => flattenToFields(v) match {
          case None => List(k -> v)
          case Some(fields) => fields.map {
            case (innerK, innerV) => combineKeys(k, innerK) -> innerV
          }
        }
      }
    )

  flattenToFields(value).fold(value)(Json.fromFields)
}

Di sini metode flattenToFields internal kami mengambil setiap nilai JSON dan mengembalikan None jika itu adalah nilai objek non-JSON, sebagai sinyal bahwa bidang itu tidak perlu diratakan, atau Some berisi urutan bidang yang diratakan dalam kasus objek JSON.

Jika kita memiliki nilai JSON seperti ini:

val Right(doc) = io.circe.jawn.parse("""{
   "foo": true,
   "bar": {
      "baz": 1,
      "qux": {
        "msg": "hello world",
        "wow": [null]
      }
   }
}""")

Kami dapat memverifikasi bahwa flatten melakukan apa yang kami inginkan seperti ini:

scala> flatten(_ + "_" + _)(doc)
res1: io.circe.Json =
{
  "foo" : true,
  "bar_baz" : 1,
  "bar_qux_msg" : "hello world",
  "bar_qux_wow" : [
    null
  ]
}

Perhatikan bahwa flattenToFields bukan rekursif ekor, dan akan meluap tumpukan untuk objek JSON yang sangat bersarang, tetapi mungkin tidak sampai kedalaman Anda beberapa ribu level, jadi dalam praktiknya tidak mungkin menjadi masalah. Anda bisa membuatnya menjadi rekursif tanpa terlalu banyak kesulitan, tetapi dengan mengorbankan overhead tambahan untuk kasus umum di mana Anda hanya memiliki beberapa lapisan sarang.

5
Travis Brown 20 September 2019, 10:04