json - 使用 Circe 展平嵌套 JSON 对象

标签 json scala circe

假设我有一个像这样的 JSON 对象:

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

我想将其递归地展平为单层,并将键与下划线合并:

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

如何使用 Circe 执行此操作?

(注意:这是 Circe Gitter channel 的另一个常见问题解答。)

最佳答案

您可以使用递归方法在 Circe 中轻松完成此操作:

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)
}

这里,我们的内部 flattenToFields 方法接受每个 JSON 值,如果它是非 JSON 对象值,则返回 None,作为该字段不需要展平的信号,或者在 JSON 对象的情况下包含一系列扁平化字段的 Some

如果我们有这样的 JSON 值:

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

我们可以验证 flatten 是否达到了我们想要的效果:

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

请注意,flattenToFields 不是尾递归,对于深度嵌套的 JSON 对象,它会溢出堆栈,但可能直到深度达到数千层时才会溢出,因此这不太可能成为问题实践。您可以使其尾部递归,而不会有太多麻烦,但在只有几层嵌套的常见情况下,会产生额外的开销。

关于json - 使用 Circe 展平嵌套 JSON 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58026172/

相关文章:

php - 错误未定义属性 : stdClass while trying to parse json file in php

scala - 在哪里可以找到 scaladoc 2 的教程?

json - Circe:高效解码多级ADT

scala - 使用 circe 时如何在 Scala 中表示动态 JSON 键

java - 使用 GET REST 调用提取以 json 格式返回的不同值

json - 替换 EAV 时 JSON(B) 中的数据完整性

javascript - json_encode 和 JSON.parse 不协调

scala - 如何让 HBase 与 sbt 的依赖管理很好地配合?

java - 如何在 Scala 中向枚举添加方法?

json - 使用 Circe 将包含 HList 的案例类解析为 JSON 字符串