如何在Kotlin中解析嵌套数组结构的JSON数据
解决JSON数组数组到Kotlin数据类的解析问题
你的JSON结构是数组的数组(每个元素是包含8个元素的有序数组,对应TermBank的8个字段),但Gson和Kotlin序列化默认都是按键值对格式的JSON对象来解析数据类的,所以才会出现"Expected BEGIN_OBJECT but was BEGIN_ARRAY"的错误。下面分别给出两种库的解决方法:
方案一:用Gson自定义TypeAdapter
写一个TypeAdapter,手动把数组的每个元素映射到TermBank的字段:
import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonWriter import com.google.gson.JsonSyntaxException class TermBankTypeAdapter : TypeAdapter<TermBank>() { override fun write(out: JsonWriter?, value: TermBank?) { // 若不需要序列化JSON,此方法可留空;如需实现,按数组格式写入即可 out?.apply { beginArray() value?.let { value(it.text) value(it.reading) value(it.tags) value(it.rules) value(it.popularity) beginArray() it.definition.forEach { def -> value(def) } endArray() value(it.sequenceNumber) value(it.tags2) } endArray() } } override fun read(`in`: JsonReader?): TermBank { return `in`?.run { beginArray() // 按JSON数组的顺序依次读取每个字段 val text = nextString() val reading = nextString() val tags = nextString() val rules = nextString() val popularity = nextInt() // 解析嵌套的definition数组 beginArray() val definition = mutableListOf<String>() while (hasNext()) { definition.add(nextString()) } endArray() val sequenceNumber = nextInt() val tags2 = nextString() endArray() TermBank(text, reading, tags, rules, popularity, definition, sequenceNumber, tags2) } ?: throw JsonSyntaxException("无效的JSON输入") } }
使用这个Adapter解析:
import com.google.gson.GsonBuilder val gson = GsonBuilder() .registerTypeAdapter(TermBank::class.java, TermBankTypeAdapter()) .create() val termBankList = gson.fromJson<Array<TermBank>>(fileString, Array<TermBank>::class.java)
方案二:用Kotlin序列化自定义Serializer
首先给数据类加上序列化注解,并指定自定义的Serializer:
import kotlinx.serialization.Serializable import kotlinx.serialization.KSerializer import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.element import kotlinx.serialization.encoding.CompositeDecoder import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.decodeStructure import kotlinx.serialization.json.Json import kotlinx.serialization.serializer @Serializable(with = TermBankSerializer::class) data class TermBank ( val text: String, val reading: String, val tags: String, val rules: String, val popularity: Int, val definition: List<String>, val sequenceNumber: Int, val tags2: String, ) object TermBankSerializer : KSerializer<TermBank> { override val descriptor: SerialDescriptor = buildClassSerialDescriptor("TermBank") { element<String>("text") element<String>("reading") element<String>("tags") element<String>("rules") element<Int>("popularity") element<List<String>>("definition") element<Int>("sequenceNumber") element<String>("tags2") } override fun serialize(encoder: Encoder, value: TermBank) { // 无需序列化的话,此方法可留空 } override fun deserialize(decoder: Decoder): TermBank { return decoder.decodeStructure(descriptor) { var text = "" var reading = "" var tags = "" var rules = "" var popularity = 0 var definition = emptyList<String>() var sequenceNumber = 0 var tags2 = "" // 按数组顺序读取所有元素 if (decodeSequentially()) { text = decodeStringElement(descriptor, 0) reading = decodeStringElement(descriptor, 1) tags = decodeStringElement(descriptor, 2) rules = decodeStringElement(descriptor, 3) popularity = decodeIntElement(descriptor, 4) definition = decodeSerializableElement(descriptor, 5, ListSerializer(String.serializer())) sequenceNumber = decodeIntElement(descriptor, 6) tags2 = decodeStringElement(descriptor, 7) } else { // 处理非顺序解析的情况(按索引读取) while (true) { when (val index = decodeElementIndex(descriptor)) { 0 -> text = decodeStringElement(descriptor, index) 1 -> reading = decodeStringElement(descriptor, index) 2 -> tags = decodeStringElement(descriptor, index) 3 -> rules = decodeStringElement(descriptor, index) 4 -> popularity = decodeIntElement(descriptor, index) 5 -> definition = decodeSerializableElement(descriptor, index, ListSerializer(String.serializer())) 6 -> sequenceNumber = decodeIntElement(descriptor, index) 7 -> tags2 = decodeStringElement(descriptor, index) CompositeDecoder.DECODE_DONE -> break else -> error("意外的索引:$index") } } } TermBank(text, reading, tags, rules, popularity, definition, sequenceNumber, tags2) } } }
最后执行解析:
val termBankList = Json.decodeFromString<Array<TermBank>>(fileString)
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

