1

我有一个带有嵌套字段的 JSON 模型,该模型从空开始,我需要一点一点地添加/删除内容。

这是带有默认值的 JSON 结构

{
  "id": "",
  "name": "",
  "age": 0,
  "address": {
    "streetName": "",
    "streetNumber": 0
  }
}

到目前为止,我尝试将 JSON 表达为String和通过 Kotlin data class(使用 Moshi 或 Gson 库),但两者都不允许我轻松更改嵌套属性。

我想要的是执行以下操作的功能

fun <T>addToJson(key: String, value: T) {
  // Finds the key in the JSON, if nested, maybe expressing the whole path to it (i.e. address.streetName)
  // Inserts the value in it
  // Bonus points if there was a way to 'determine' the type of the field so that I don't risk to set for the key `streetNumber` a value that is `String`
}

最终目标是能够从应用程序中的任何位置调用,例如addToJson("path.to.key", 25)使用表示为String或以任何其他简单方式表示的键

4

2 回答 2

0

在 Jackson (jackson-databind) 库中尝试 ObjectNode

您可以从头开始构建它

val factory = JsonNodeFactory(true)
val o = ObjectNode(factory)
o.set("id", IntNode(15))
o.set("name", TextNode("yourname"))
o.set("lastName", TextNode("lastname"))
val address = ObjectNode(factory)
o.set("address", address)
address.set("streetName", TextNode("Lenin"))
address.set("streetNumber", IntNode(5))
address.set("buildingNumber", IntNode(15))
println(o)

或加载现有的 json 并对其进行修改

val json = "{\n" +
        "  \"id\": \"\",\n" +
        "  \"name\": \"\",\n" +
        "  \"age\": 0,\n" +
        "  \"address\": {\n" +
        "    \"streetName\": \"\",\n" +
        "    \"streetNumber\": 0\n" +
        "  }\n" +
        "}"
val o : ObjectNode = (ObjectMapper()).readTree(json) as ObjectNode
o.set("id", IntNode(15))
o.set("name", TextNode("yourname"))
val address = o.get("address") as ObjectNode
address.set("streetName", TextNode("Lenin"))
address.set("streetNumber", IntNode(5))
address.set("buildingNumber", IntNode(15))
println(o)

我不知道在 Json 中支持多级路径的库。但是实现这样的东西相当容易:

fun setInJson(root: ObjectNode, objectMapper: ObjectMapper, path: String, value: JsonNode) {
    val splitPath = path.split(":")
    val lastName = splitPath.last()
    val notLastNames = splitPath.subList(0, splitPath.size - 1)
    var node = root
    notLastNames.forEach { nodeName ->
        node = (node.get(nodeName) as ObjectNode?) ?: {
            val newNode = objectMapper.createObjectNode()
            node.set(nodeName, newNode)
            newNode
        }()
    }
    node.set(lastName, value)
}

可以用作:

val json = "{\n" +
        "  \"id\": \"\",\n" +
        "  \"name\": \"\",\n" +
        "  \"age\": 0,\n" +
        "  \"address\": {\n" +
        "    \"streetName\": \"\",\n" +
        "    \"streetNumber\": 0\n" +
        "  }\n" +
        "}"

val om = ObjectMapper()
val o : ObjectNode = (ObjectMapper()).readTree(json) as ObjectNode
setInJson(o, om, "id", IntNode(15))
setInJson(o, om, "name", TextNode("yourname"))
setInJson(o, om, "address:streetName", TextNode("Lenin"))
setInJson(o, om, "address:streetNumber", IntNode(5))
println(o)
于 2019-11-12T13:42:29.270 回答
0

这个伪你问的一些问题。

  1. 如果多次使用相同的嵌套键,您打算做什么?
  2. T 值必须是已知的 JSON 对象类型基元数组或 JSON 对象您打算如何在运行时执行此操作?

这是一个关于如何访问对象内每个属性的示例

val jsonString = "{\n" +
        "  \"id\": \"\",\n" +
        "  \"name\": \"\",\n" +
        "  \"age\": 0,\n" +
        "  \"address\": {\n" +
        "    \"streetName\": \"\",\n" +
        "    \"streetNumber\": 0\n" +
        "  }\n" +
        "}"
val gson = Gson()
val jsonElement = gson.fromJson(jsonString, JsonElement::class.java).asJsonObject
jsonElement.addProperty("id",26)
jsonElement.addProperty("name","sof")
jsonElement.addProperty("age",33)
val nested = jsonElement.get("address").asJsonObject
nested.addProperty("streetName","blala")
nested.addProperty("streetNumber",12)

print(jsonElement)
于 2019-11-12T13:35:44.653 回答