android - 使用动态数据解析非常大的 JSON 文件

标签 android json kotlin klaxon

我需要解析从服务器下载的非常大的 JSON 文件。这些 JSON 文件可以包含完全不同的键和值。这里有些例子...

{ "result": "PASS", 
  "items": [ 
    { "name": "John", "age": 33 }, 
    { "name": "Jane", "age": 23 } ] 
}


{ "result": "PASS", 
  "items": [ 
    { "make": "Ford", "model": "Mustang", "colors": ["blue", "red", "silver"] }, 
    { "make": "Dodge", "model": "Charger", "colors": ["yellow", "black", "silver"] } ] 
}
items数组可能包含数千个条目,每个项目中的数据最多可以包含 60 个键/值对。
这些只是两个示例,但我需要能够解析 30-40 种不同类型的 JSON 文件,而且我不能总是控制文件中的数据类型。因此,我无法创建自定义模型来将数据绑定(bind)到我的应用程序中的对象。
我想做的是创建一个 JsonObject对于 items 中的每个项目数组并将其添加到 MutableList我可以在应用程序中使用。我目前正在使用 Klaxon Streaming API 来尝试完成此操作,但似乎可以找到一种无需绑定(bind)到自定义对象的方法。
JsonReader(StringReader(testJson)).use { reader ->
        reader.beginObject {
            var result: String? = null
            while (reader.hasNext()) {
                val name = reader.nextName()
                when (name) {
                    "result" -> result = reader.nextString()
                    "items" -> {
                        reader.beginArray {
                            while (reader.hasNext()) {
                                // ???
                            }
                        }
                    }
                }
            }
        }
    }

最佳答案

如果您无论如何都要将所有项目收集到一个列表中(而不是立即一个接一个地处理它们),那么使用流 API 没有多大意义。它可以做得更简单:

val response = Klaxon().parseJsonObject(StringReader(testJson))
val result = response["result"]
val items = response.array<JsonObject>("items") ?: JsonArray()
...
流处理涉及更多。首先,您要确保在开始处理之前服务器响应未完全读入内存(即解析器输入不应是字符串,而是输入流。详细信息取决于您的 http 客户端库选择)。其次,您需要提供某种回调,以便在元素到达时对其进行处理,例如:
fun parse(input: Reader, onResult: (String) -> Unit, onItem: (JsonObject) -> Unit)  {

    JsonReader(input).use { reader ->
        reader.beginObject {
            while (reader.hasNext()) {
                when (reader.nextName()) {
                    "result" -> onResult(reader.nextString())
                    "items" -> reader.beginArray {
                        while (reader.hasNext()) {
                            val item = Parser(passedLexer = reader.lexer, streaming = true).parse(reader) as JsonObject
                            onItem(item)
                        }
                    }
                }
            }
        }
    }
}

fun main(args: Array<String>) {

    // "input" simulates the server response 
    val input = ByteArrayInputStream(testJson.encodeToByteArray())

    InputStreamReader(input).use {
        parse(it,
            onResult = { println("""Result: $it""") },
            onItem = { println(it.asIterable().joinToString(", ")) }
        )
    }
}
最好将 Klaxon 与 Kotlin Flow 或 Sequence 集成,但我发现这很困难,因为 beginObject 和 beginArray 包装器不能很好地与挂起函数配合使用。

关于android - 使用动态数据解析非常大的 JSON 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64381056/

相关文章:

java - 通过 Spring 更正 JSON REST Controller

kotlin - 如何从 lambda 引用外部函数?

ios - 单个 JSON 返回的多个可编码对象类型

java - adb logcat 返回 "Logcat read failure"

Android 相机 : Difference between PictureCallback, ShutterCallback 和 PreviewCallback

android - 如何在 Android 上使用 OpenSSL?

JQuery Ajax POST 调用内容类型为 JSON 的 Jersey 无法执行

function - 通用顶级功能引用

Kotlin + Mockito + NullPointerException stub 时抛出

android - 访问 Activity 的标准选项菜单