遍历嵌套的 JsonObject
Traverse through nested JsonObject
我在我的应用程序中使用 Gson 解析 JSON。我有一个特定的用例,我想获取一个 JsonObject 并有效地深度克隆它,除了改变符合某些特定条件的 key/value。
例如,假设源对象是这样的:
{
"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()
开始迭代,但是这个 returns 一个 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
}
在朋友的帮助下,我找到了这个问题的答案。
希望这能帮助将来遇到同样问题的其他人。
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 来代替它。
我在这里提供的解决方案掩盖了那个细节,因为它有点绕了弯路,但是你可以看到在哪里会发生这种转换。
我在我的应用程序中使用 Gson 解析 JSON。我有一个特定的用例,我想获取一个 JsonObject 并有效地深度克隆它,除了改变符合某些特定条件的 key/value。
例如,假设源对象是这样的:
{
"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()
开始迭代,但是这个 returns 一个 Map
编辑:
对我来说,最好将 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
}
在朋友的帮助下,我找到了这个问题的答案。 希望这能帮助将来遇到同样问题的其他人。
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 来代替它。
我在这里提供的解决方案掩盖了那个细节,因为它有点绕了弯路,但是你可以看到在哪里会发生这种转换。