JSON: Nested data
● Intermediate3 min
Objects inside objects and lists inside them: chain reads to go down, or decode the whole shape into records inside records.
use std.json
fn main() ! Error {
const text = """
\{
"order": \{
"id": 7,
"customer": \{ "name": "Asha", "city": "Pune" },
"items": [
\{ "name": "pen", "price": 20 },
\{ "name": "ink", "price": 45 }
]
}
}
"""
const doc = try json.parse(text)
const order = doc["order"]
print(order["customer"]["name"].text() ?? "")
print(order["items"][1]["price"].int() ?? 0)
let total = 0
for item in order["items"].list() ?? [] {
total += item["price"].int() ?? 0
}
print("{order["items"].len()} items, {total} in all")
print(order["customer"]["phone"]["mobile"].text() ?? "no phone")
}The program ran and printed:
kavach run nested.kav
Asha452 items, 65 in allno phone
order["items"][1]["price"]goes down one level at a time: a key for an object, a position for an array..list()gives an array's items, to loop over.- A path that isn't there, however deep, ends in
Null:no phone.
When you know the shape, write it as types, and one call reads it all, checked at every level:
use std.json
type Customer {
name: String
city: String
}
type Item {
name: String
price: Int
}
type Order {
id: Int
customer: Customer
items: [Item]
}
fn main() ! Error {
const text = """
\{ "id": 7, "customer": \{ "name": "Asha", "city": "Pune" },
"items": [ \{ "name": "pen", "price": 20 }, \{ "name": "ink", "price": 45 } ] }
"""
const order = try json.decode<Order>(text)
print(order.customer.city)
print(order.items.map(i => i.name))
print(order.items.sum(i => i.price))
}The program ran and printed:
kavach run nested-decode.kav
Pune["pen", "ink"]65