You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中使用GSON解析含动态键名的JSON数据?

在Kotlin中用GSON解析动态结构的JSON

问题描述

我有如下JSON结构:

{"codemap":{"codeOfItem1":"titleOfItem1","codeOfItem2":"titleOfItem2","codeOfItem3":"titleOfItem3","codeOfItem4":"titleOfItem4"},"items":{"titleOfItem1":{"attribute1":"value1","atttribute2":{"subattr1":"value1_of_subattr1_for_item1","subattr2":"value1_of_subattr2_for_item1"}},"titleOfItem2":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item2","subattr2":"value1_of_subattr2_for_item2"}},"titleOfItem3":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item3","subattr2":"value1_of_subattr2_for_item3"}},"titleOfItem4":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item4","subattr2":"value1_of_subattr2_for_item4"}}}}

其中titleOfItemXXX既是codemap中的值,也是items中的键名。由于生产环境中条目数量和键名不确定,不想用手动解析或固定数据类,请问如何在Kotlin中使用GSON解析该JSON?

解决方案

方式1:使用Gson的JsonObject直接处理

这种方式完全适配动态结构,灵活度最高:

import com.google.gson.Gson
import com.google.gson.JsonObject

fun main() {
    val jsonString = """{"codemap":{"codeOfItem1":"titleOfItem1","codeOfItem2":"titleOfItem2","codeOfItem3":"titleOfItem3","codeOfItem4":"titleOfItem4"},"items":{"titleOfItem1":{"attribute1":"value1","atttribute2":{"subattr1":"value1_of_subattr1_for_item1","subattr2":"value1_of_subattr2_for_item1"}},"titleOfItem2":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item2","subattr2":"value1_of_subattr2_for_item2"}},"titleOfItem3":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item3","subattr2":"value1_of_subattr2_for_item3"}},"titleOfItem4":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item4","subattr2":"value1_of_subattr2_for_item4"}}}}"""
    
    val gson = Gson()
    val rootObject = gson.fromJson(jsonString, JsonObject::class.java)
    
    // 提取codemap并遍历
    val codeMap = rootObject.getAsJsonObject("codemap")
    codeMap.entrySet().forEach { (code, titleJson) ->
        val title = titleJson.asString
        // 根据title从items中获取对应数据
        val itemObject = rootObject.getAsJsonObject("items").getAsJsonObject(title)
        
        // 读取属性值
        val attribute1 = itemObject.get("attribute1").asString
        val subAttr1 = itemObject.getAsJsonObject("atttribute2").get("subattr1").asString
        
        println("Code: $code, Title: $title, Attribute1: $attribute1, SubAttr1: $subAttr1")
    }
}

方式2:用嵌套Map映射动态结构

贴近Kotlin集合操作习惯,无需额外定义类:

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

fun main() {
    val jsonString = """{"codemap":{"codeOfItem1":"titleOfItem1","codeOfItem2":"titleOfItem2","codeOfItem3":"titleOfItem3","codeOfItem4":"titleOfItem4"},"items":{"titleOfItem1":{"attribute1":"value1","atttribute2":{"subattr1":"value1_of_subattr1_for_item1","subattr2":"value1_of_subattr2_for_item1"}},"titleOfItem2":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item2","subattr2":"value1_of_subattr2_for_item2"}},"titleOfItem3":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item3","subattr2":"value1_of_subattr2_for_item3"}},"titleOfItem4":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item4","subattr2":"value1_of_subattr2_for_item4"}}}}"""
    
    val gson = Gson()
    // 定义嵌套Map的类型
    val rootType = object : TypeToken<Map<String, Map<String, Any>>>() {}.type
    val rootMap: Map<String, Map<String, Any>> = gson.fromJson(jsonString, rootType)
    
    val codeMap = rootMap["codemap"] as Map<String, String>
    val itemsMap = rootMap["items"] as Map<String, Map<String, Any>>
    
    // 关联codemap和items数据
    codeMap.forEach { (code, title) ->
        val item = itemsMap[title] ?: return@forEach
        val attribute1 = item["attribute1"] as String
        val subAttrMap = item["atttribute2"] as Map<String, String>
        val subAttr1 = subAttrMap["subattr1"]
        
        println("Code: $code, Title: $title, Attribute1: $attribute1, SubAttr1: $subAttr1")
    }
}

方式3:半固定数据类+Map(兼顾类型安全与动态性)

如果Item内部属性固定,仅外部键名动态,可采用这种方式:

import com.google.gson.Gson
import com.google.gson.annotations.SerializedName

// 定义Item的固定结构(注意匹配原JSON的拼写)
data class Item(
    val attribute1: String,
    @SerializedName("atttribute2")
    val attribute2: SubAttribute
)

data class SubAttribute(
    val subattr1: String,
    val subattr2: String
)

// 外层用Map接收动态键
data class RootData(
    val codemap: Map<String, String>,
    val items: Map<String, Item>
)

fun main() {
    val jsonString = """{"codemap":{"codeOfItem1":"titleOfItem1","codeOfItem2":"titleOfItem2","codeOfItem3":"titleOfItem3","codeOfItem4":"titleOfItem4"},"items":{"titleOfItem1":{"attribute1":"value1","atttribute2":{"subattr1":"value1_of_subattr1_for_item1","subattr2":"value1_of_subattr2_for_item1"}},"titleOfItem2":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item2","subattr2":"value1_of_subattr2_for_item2"}},"titleOfItem3":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item3","subattr2":"value1_of_subattr2_for_item3"}},"titleOfItem4":{"attribute1":"value2","atttribute2":{"subattr1":"value1_of_subattr1_for_item4","subattr2":"value1_of_subattr2_for_item4"}}}}"""
    
    val gson = Gson()
    val rootData = gson.fromJson(jsonString, RootData::class.java)
    
    // 遍历关联数据
    rootData.codemap.forEach { (code, title) ->
        val item = rootData.items[title] ?: return@forEach
        println("Code: $code, Title: $title, Attribute1: ${item.attribute1}, SubAttr1: ${item.attribute2.subattr1}")
    }
}

内容的提问来源于stack exchange,提问作者Tauri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:55:27