Rust - Serde - Iterating Over JSON keys

09/26/2021, Sun
Categories: #rust #shell

Retrieving data from JSON

The usefulness of reading a JSON file with Serde is being able to iterate over the data, and as a continuation of the post in serde - Read JSON File, this article will focus on looping over data once a JSON file data has been read.

Update the JSON file to include a "people" key and each of the person object will be placed inside an array for the "people" key's value.

[
    {
        "people": [
            {
                "name": "Bob",
                "gender": "male",
                "age": 34
            },
            {
                "name": "Alice",
                "gender": "female",
                "age": 32
            }
        ]
    }
]

The following example assumes that not much is known about the structure of the JSON data, so values will be generic when appropriate.

In main.rs, import the Value from the serde_json package and the HashMap from std::collections. These imports will help define the shape of the JSON data:

use serde_json::{Value};
use std::collections::HashMap;
use std::fs;

...

The main function will need to output a type of Result<(), serde_json::Error> because the use of serde_json::from_str(&json)? requires that the return value within the function is of type Result or Option.

use serde_json::Value;
use std::collections::HashMap;
use std::fs;

fn main() -> Result<(), serde_json::Error> {
    let json = fs::read_to_string("./persons.json").expect("Unable to read file");

    let sub_values: Vec<HashMap<String, Value>> = serde_json::from_str(&json)?;

    Ok(())
}

The definition of the serde result JSON data will be a Vec<HashMap<String, Value>> since the JSON needs iterating over an array, and this array contains an object with a key of "people".

use serde_json::Value;
use std::collections::HashMap;
use std::fs;

fn main() -> Result<(), serde_json::Error> {
    let json = fs::read_to_string("./persons.json").expect("Unable to read file");

    let sub_values: Vec<HashMap<String, Value>> = serde_json::from_str(&json)?;

    // Print out the first key value of the object.
    for item in sub_values.iter() {
        dbg!(&item["people"]);

        // Print: Get the keys from the object
        dbg!(item.keys());
    }

    Ok(())
}

The resultant output after running cargo run:

[src/main.rs:12] &item["people"] = Array([
    Object({
        "age": Number(
            34,
        ),
        "gender": String(
            "male",
        ),
        "name": String(
            "Bob",
        ),
    }),
    Object({
        "age": Number(
            32,
        ),
        "gender": String(
            "female",
        ),
        "name": String(
            "Alice",
        ),
    }),
])
[src/main.rs:15] item.keys() = [
    "people",
]