kotlinx-serialization-jsonpath
2.0.0-alpha.1indexedOffers a DSL to work with JSON elements, allowing selection and modification of JSON properties, including deeply nested and array elements, with type-safe operations and path notation.
Offers a DSL to work with JSON elements, allowing selection and modification of JSON properties, including deeply nested and array elements, with type-safe operations and path notation.
JsonPath offers a simple DSL to work with JsonElement from Kotlinx Serialization Json,
this allows you to easily work with JSON in Kotlin in a typed manner.
Simply add the following dependency as implementation in the build.gradle dependencies` block.
dependencies {
implementation("io.github.nomisrev:kotlinx-serialization-jsonpath:0.2.0")
}
Let's dive right in with following JSON_STRING as input JsonElement that models a simple company.
Given this we can the from the . This gives us an from the to the property with type . We can then use this to the original 's property, this gives us back with the modified according to the passed function.
val json: JsonElement = Json.decodeFromString(JSON_STRING)
val name: Optional<JsonElement, String> = JsonPath.select("name").string
println(name.modify(json, String::uppercase))
You can get the full code here.
{"name":"ARROW","address":{"city":"Functional Town","street":{"number":1337,"name":"Functional street"}},"employees":[{"name":"John","lastName":"doe"},{"name":"Jane","lastName":"doe"}]}
As we've seen above we can select a property from a JsonObject,
but what if we want to access deeply nested properties in our JsonElement?
For that we can use path which allows you to select deeply nested properties using the dot (.) notation you might know from Javascript.
Below we select the address JsonObject,
and from the address JsonObject we then select the street JsonObject,
to then finally the of the .
This again returns us an Optional<JsonElement, String>, which we use to modify the address.street.name.
We then also extract the value using getOrNull which returns us the desired in our ,
or it returns if the desired is not available in our .
val json: JsonElement = Json.decodeFromString(JSON_STRING)
val name: Optional<JsonElement, String> = JsonPath.path("address.street.name").string
val res: JsonElement = name.modify(json, String::uppercase).also(::println)
name.getOrNull(res)?.also(::println)
You can get the full code here.
{"name":"Arrow","address":{"city":"Functional Town","street":{"number":1337,"name":"FUNCTIONAL STREET"}},"employees":[{"name":"John","lastName":"doe"},{"name":"Jane","lastName":"doe"}]}
FUNCTIONAL STREET
In the previous examples we've seen how we can select properties out of JsonObject,
but when working with JsonElement we also often have to deal with JsonArray that can contain many JsonElement.
For these use-cases we can use every, which focuses into every JsonElement in our .
In the example below we select the employees JsonArray,
and then we select every JsonElement in the JsonArray.
We then select the name out of every JsonElement.
Instead of Optional<JsonElement, String> it now returns Traversal<JsonElement, String>,
since we selected many properties instead of a single property.
Just like before we can apply a function to it using modify,
and we can also extract every property using getAll.
This returns us an emptyList() when no values were found along the path,
or all found values inside a List.
val json: JsonElement = Json.decodeFromString(JSON_STRING)
val employeesName: Traversal<JsonElement, String> = JsonPath.select("employees").every.select("name").string
val res: JsonElement = employeesName.modify(json, String::uppercase).also(::println)
employeesName.getAll(res).also(::println)
You can get the full code here.
{"name":"Arrow","address":{"city":"Functional Town","street":{"number":1337,"name":"Functional street"}},"employees":[{"name":"JOHN","lastName":"doe"},{"name":"JANE","lastName":"doe"}]}
[JOHN, JANE]
Alternatively we can also use the pathEvery function to select every JsonElement in our JsonArray.
Like for path we can also use the dot (.) notation to select deeply nested properties.
On the other hand, the star (*) notation allow us to select in our .
Like before, below we select the employees JsonArray,
and then we select every JsonElement in the JsonArray.
We then select the name out of every JsonElement.
Again, instead of Optional<JsonElement, String> it now returns Traversal<JsonElement, String>,
since we selected many properties instead of a single property.
You can then, apply a function to it using modify like before.
val json: JsonElement = Json.decodeFromString(JSON_STRING)
val employeesName: Traversal<JsonElement, String> = JsonPath.pathEvery("employees.*.name").string
val res: JsonElement = employeesName.modify(json, String::uppercase).also(::println)
employeesName.getAll(res).also(::println)
You can get the full code here.
{"name":"Arrow","address":{"city":"Functional Town","street":{"number":1337,"name":"Functional street"}},"employees":[{"name":"JOHN","lastName":"doe"},{"name":"JANE","lastName":"doe"}]}
[JOHN, JANE]
{
"name": "Arrow",
"address": {
"city": "Functional Town",
"street": {
"number": 1337,
"name": "Functional street"
}
},
"employees": [
{
"name": "John",
"lastName": "doe"
},
{
"name": "Jane",
"lastName": "doe"
}
]
}
JsonElementnameJsonElementOptionalJsonElementnameStringJsonElementnameJsonElementString::uppercaseJsonElementJsonElementJsonArrayJsonElementJsonArraySurfaced from shared tags and platforms — no rankings paid for.