How to Iterate Over JSON objects with hierarchy?

Hi,
I am very new to Rust and basically from JavaScript background.

I have a problem below where i want to print “name” of each contact in the object deep down the hierarchy.
The contact object as in JavaScript may not be having exact same number of fields every time to make a suitable Structure.

Could you please help how to achieve this in Rust.

Thanks in Advance!

extern crate serde_json;

use serde_json::{Value, Error};
use std::collections::HashMap;

fn untyped_example() -> Result<(), Error> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"{
                    "name": "John Doe",
                    "age": 43,
                    "phones": [
                      "+44 1234567",
                      "+44 2345678"
                    ],
                    "contact": {
                           "name": "Stefan",
                            "age": 23,
                             "optionalfield": "dummy field",
                            "phones": [
                              "12123",
                              "345346"
                            ],
                            "contact": {
                                   "name": "James",
                                    "age": 34,
                                    "phones": [
                                      "23425",
                                      "98734"
                                    ]
                            }
                    }
                  }"#;

    let mut d:HashMap<String, Value> = serde_json::from_str(&data)?;
    for (str, val) in d {
        println!("{}", str);
        if str == "contact" {
            d = serde_json::from_value(val)?;
        }
    }

    Ok(())
}

fn main() {
    untyped_example().unwrap();
}

By default, serde ignores keys not in the structure, and handles sometimes present keys using Option. So this will work out of the box with a structure like this:

#[derive(Deserialize)]
struct Person {
    name: String,
    age: u32,
    // add more fields you want here, wrap optional ones in Option<>, for example:
    //phones: Vec<String>,
    //optionalfield: Option<String>,
    // the recursive case needs Box to avoid infinite struct sizes
    contact: Option<Box<Person>>,
}

// then:
let person: Person = serde_json::from_str(&data)?;
1 Like

This solution works really well when:

  • you know enough about the incoming data to be sure that it has this shape (so parsing won’t fail), and
  • you need only some parts of the data (so it’s fine to ignore the rest).

If those things aren’t both true, serde still has some other useful tricks for you. In reverse order to above:

The latter case is as close as it’s possible to come to arbitrary JSON ingestion in a more dynamic language like JavaScript or Perl. The type structure encodes all the same information about content (this key held a JSON array or string or…) as you’d get by introspection of the native data tree there.

On the other hand if you know more about the shape of the data above, there’s another useful thing. Instead of options, if there are a few variants of a contact with some specific differences, you can parse them into an enum of structs representing each variant: https://serde.rs/enum-representations.html#untagged