【问题标题】:Traverse through nested JsonObject遍历嵌套的 JsonObject
【发布时间】:2021-05-28 23:48:57
【问题描述】:

我在我的应用程序中使用 Gson 来解析 JSON。我有一个特殊的用例,我想获取一个 JsonObject 并有效地深度克隆它,除了更改与某些特定条件匹配的键/值。

例如,假设源对象是这样的:

{
  "foo": {
    "bar": {
      "baz": "some value here"
    },
    "baz": "another value here"
  }
}

我想遍历每个键(不管它是如何嵌套的),如果有一个名为 baz 的键,我将运行我的转换函数,我的输出对象将如下所示:

{
  "foo": {
    "bar": {
      "bazTransformed": "this got altered by my function"
    },
    "bazTransformed": "so did this"
  }
}

我知道我可以做一些事情,比如将 JsonObject 转换为字符串并使用 RegEx 模式来查找和替换,但这并不感觉正确。

我真的很难理解创建递归函数,或者至少是比字符串操作更好的解决方案。

我可以使用JsonObject.entrySet() 开始迭代,但这会返回一个 Map - 这似乎增加了更多复杂性,因为我需要先检查 JsonElement 是否是 JsonObject,然后才能以某种方式继续递归。

编辑: 对我来说,最好将 JsonObject 转换为 Map ,如下所示: gson.fromJson(sourceObj, Map::class.java) as MutableMap<*, *>

我可以编写一个像这样递归迭代的函数:

fun generateObject(sourceObj: JsonElement): JsonObject {
    val inputMap = gson.fromJson(sourceObj, Map::class.java) as MutableMap<*, *>

    val outputMap: MutableMap<String, Any> = mutableMapOf()

    fun go(toReturn: MutableMap<String,Any>,
           input: MutableMap<String, Any>) {
            for ((key, value) in input) {
                if (key == "baz") {
                    println("baz key found")
                    //do my transformation here

                }
                if (value is Map<*, *>) {
                    println("nested map")
                    go(toReturn, value as MutableMap<String, Any>)
                }
                // this part is wrong however, because `key` is potentially nested
                outputMap[key] = value
            }

    }

    go(outputMap, inputMap as MutableMap<String, Any>)

    return gson.toJsonTree(outputMap).asJsonObject
}

【问题讨论】:

  • 您对entrySet 的建议很可能是实现这一点的最佳方式。
  • 看看 JsonPath,一个解决这类问题的 DSL:stackoverflow.com/questions/27244431/…
  • 感谢@fluffy - 我查看了 JsonPath,为了让它为我工作,我想我需要遍历树,在稍后传递给 JsonPath 时构造一个字符串路径。例如:foo.bar.baz。但是,我在想,如果我已经能够递归地遍历每个节点,那么我应该能够构建一个我得到的对象(一个 Gson JsonObject,甚至是一个Map&lt;*, *&gt;,然后用 Gson 将它转换为一个 JsonObject .

标签: kotlin recursion functional-programming gson


【解决方案1】:

在朋友的帮助下,我找到了这个问题的答案。 希望这可以帮助将来遇到同样问题的其他人。

  val inputMap = mapOf(
      "foo" to mapOf(
          "bar" to mapOf(
              "baz" to "something composable")))

  val expectedOutputMap = mutableMapOf(
      "foo" to mutableMapOf(
          "bar" to mutableMapOf(
              "bux" to "here be some data")))
    
 
    
    fun go(input: Map<String, Any>) : Map<String, Any> {
      return input.entries.associate {
        if (it.key == "baz") {
          // alternatively, call some transformation function here
            "bux" to "here be some data"
        } else if ( it.value is Map<*, *>) {
            it.key to go(it.value as Map<String, Any>)
        } else {
            it.key to it.value                        
        }

         
      }
    }

    val outputMap = go(inputMap)

我的用例最终演变略有不同。 对于我的用例,我需要实际获取一个 JsonObject,对其进行迭代,如果我找到一个特定的键,那么我会读取该键的内容并构建一个新的 JsonElement 来代替它。

我在这里提供的解决方案掩盖了那个细节,因为它有点绕道,但你可以看到这种转换会发生在哪里。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    • 2019-08-22
    • 2017-07-25
    相关资源
    最近更新 更多