前回は、ごく簡単な json データを扱っただけなので、 今回は、もう少し複雑かつ実践的な json データを kotlinx serialization を使ってパースしてみます。
最終的にパースしたい json データはこれです。
val jsonString = """{
"list": [
{ "type": "electric",
"pokemons": [
{ "name": "Pikachu" },
{ "name": "Raichu" },
{ "name": "Voltorb" },
{ "name": "Electrode" }]},
{ "type": "water",
"pokemons": [
{ "name": "Squirtle" },
{ "name": "Wartortle" },
{ "name": "Psyduck" },
{ "name": "Golduck" }]},
{ "type": "fire",
"pokemons": [
{ "name": "Charmander" },
{ "name": "Charmeleon" },
{ "name": "Ponyta" }]},
{ "type": "rock",
"pokemons": [
{ "name": "Geodude" },
{ "name": "Graveler" },
{ "name": "Golem" }]}
]
}"""
まずは、話を簡単にするために以下の部分だけパースすることを考えます。
{ "type": "electric",
"pokemons": [
{ "name": "Pikachu" },
{ "name": "Raichu" },
{ "name": "Voltorb" },
{ "name": "Electrode" }]}
以下のコードを書きます。
json.main.kts
@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1")
import kotlinx.serialization.json.*
val jsonString = """{
"type": "electric",
"pokemons": [
{ "name": "Pikachu" },
{ "name": "Raichu" },
{ "name": "Voltorb" },
{ "name": "Electrode" }]}"""
val rootElement: JsonElement = Json.parseToJsonElement(jsonString)
val typeElement: JsonElement? = rootElement.jsonObject["type"]
println(typeElement)
実行。
$ kotlinc -script json.main.kts
"electric"
うまくいきました。
typeElement から electric 文字列を取り出すには、以下のようにします。
val typeValue: String? = typeElement?.jsonPrimitive?.contentOrNull
typeValue が決して null にならないようにしたければ、以下のようにします。
val typeValue: String = typeElement?.jsonPrimitive?.contentOrNull?:""
もし null だった場合、空文字列を返します。
次に、pokemons の部分の処理を方法を考えます。 先ほどは値が文字列でしたが、ここはリストになっているので、次のようにします。
val array: JsonArray? = rootElement.jsonObject["pokemons"]?.jsonArray
array の中身を確認したければ、次のようにします。
if(array!=null){
array.forEach {
println(it)
}
}
JsonArray? という型は扱いづらいので toList という補助関数を導入します。 これは JsonArray? を List<JsonElement> に変換する関数です。
val toList: (JsonArray?)->List<JsonElement> = { array->
if( array==null ){
listOf()
}
else {
0.until(array.size).map { index->
array.get(index)
}
}
}
作動を確認します。
val array: JsonArray? = rootElement.jsonObject["pokemons"]?.jsonArray
println(toList(array))
実行:
$ kotlinc -script json.main.kts
[{"name":"Pikachu"}, {"name":"Raichu"}, {"name":"Voltorb"}, {"name":"Electrode"}]
うまくいきました。
toList して戻ってきた値は List<JsonElement> なので、この中身をパースするには次のようにします。
toList(array).forEach { item->
val nameValue: String = item.jsonObject["name"]?.jsonPrimitive?.contentOrNull?:""
println("- ${nameValue}")
}
ここでは jsonPrimitivie が String の場合だけを扱っていますが、 もし Boolean, Int, Long, Float, Double などの場合は booleanOrNull, intOrNull, ... を使います。
ここまでのコードをまとめます。
// json.main.kts
@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1")
import kotlinx.serialization.json.*
val jsonString = """{
"type": "electric",
"pokemons": [
{ "name": "Pikachu" },
{ "name": "Raichu" },
{ "name": "Voltorb" },
{ "name": "Electrode" }]}"""
val toList: (JsonArray?)->List<JsonElement> = { array->
if( array==null ){
listOf()
}
else {
0.until(array.size).map { index->
array.get(index)
}
}
}
val rootElement: JsonElement = Json.parseToJsonElement(jsonString)
val typeElement: JsonElement? = rootElement.jsonObject["type"]
println(typeElement)
val typeValue: String? = typeElement?.jsonPrimitive?.contentOrNull
println(typeValue)
val array: JsonArray? = rootElement.jsonObject["pokemons"]?.jsonArray
toList(array).forEach { item->
val nameValue: String = item.jsonObject["name"]?.jsonPrimitive?.contentOrNull?:""
println("- ${nameValue}")
}
では、最終的にパースしたかった json データをパースします。
といっても、ここまででパースした部分が list: [{},{},...] のように list に入れてあるだけなので、 次のようにするだけの話です。
val rootElement: JsonElement = Json.parseToJsonElement(jsonString)
val list0 = toList(rootElement.jsonObject["list"]?.jsonArray)
println(list0)
list0 の各 element が先ほど上でパースした内容になる。
list0.forEach { element->
// 先ほど書いたコード
}
実行します。
$ kotlinc -script json.main.kts
electric
- Pikachu
- Raichu
- Voltorb
- Electrode
water
- Squirtle
- Wartortle
- Psyduck
- Golduck
fire
- Charmander
- Charmeleon
- Ponyta
rock
- Geodude
- Graveler
- Golem
完成したコードを掲載します。
// json.main.kts
@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1")
import kotlinx.serialization.json.*
val jsonString = """{
"list": [
{ "type": "electric",
"pokemons": [
{ "name": "Pikachu" },
{ "name": "Raichu" },
{ "name": "Voltorb" },
{ "name": "Electrode" }]},
{ "type": "water",
"pokemons": [
{ "name": "Squirtle" },
{ "name": "Wartortle" },
{ "name": "Psyduck" },
{ "name": "Golduck" }]},
{ "type": "fire",
"pokemons": [
{ "name": "Charmander" },
{ "name": "Charmeleon" },
{ "name": "Ponyta" }]},
{ "type": "rock",
"pokemons": [
{ "name": "Geodude" },
{ "name": "Graveler" },
{ "name": "Golem" }]}
]
}"""
val toList: (JsonArray?)->List<JsonElement> = { array->
if( array==null ){
listOf()
}
else {
0.until(array.size).map { index->
array.get(index)
}
}
}
val rootElement: JsonElement = Json.parseToJsonElement(jsonString)
val list0 = toList(rootElement.jsonObject["list"]?.jsonArray)
list0.forEach { element->
val typeElement: JsonElement? = element.jsonObject["type"]
val typeValue: String? = typeElement?.jsonPrimitive?.contentOrNull
println(typeValue)
val array: JsonArray? = element.jsonObject["pokemons"]?.jsonArray
toList(array).forEach { item->
val nameValue: String = item.jsonObject["name"]?.jsonPrimitive?.contentOrNull?:""
println("- ${nameValue}")
}
}
以上です。