Read and deserialize JSON file where some fields can have arbitrary values
- Defined fields: title, jobs, runs-on
- Values selected from a well defined list: ubuntu, windows
- User supplied values: test, build, "Sample file"
examples/json/deserialize-json-where-some-keys-are-arbitrary/data.json
{ "title": "Sample file", "jobs": { "test": { "runs-on": "ubuntu" }, "build": { "runs-on": "windows" } } }
Object { "jobs": Object { "build": Object { "runs-on": String("windows"), }, "test": Object { "runs-on": String("ubuntu"), }, }, "title": String("Sample file"), } -------- title: Sample file { "build": Object { "runs-on": String("windows"), }, "test": Object { "runs-on": String("ubuntu"), }, } key: "build" value: Object {"runs-on": String("windows")} key: "test" value: Object {"runs-on": String("ubuntu")} -------- data = Config { title: "Sample file", jobs: {"build": Job { runs_on: windows }, "test": Job { runs_on: ubuntu }} } title: Sample file ["build", "test"] key: "build" Job { runs_on: windows } key: "test" Job { runs_on: ubuntu }
examples/json/deserialize-json-where-some-keys-are-arbitrary/src/main.rs
use std::collections::HashMap; use serde::{Deserialize, Serialize}; #[allow(non_camel_case_types)] #[derive(Serialize, Deserialize, Debug, PartialEq)] enum Platform { linux, ubuntu, windows, macos, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] struct Job { #[serde(rename = "runs-on")] runs_on: Platform, } #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] struct Config { title: String, jobs: HashMap<String, Job>, } fn main() { let filename = "data.json"; read_any_json(filename); read_struct_json(filename); } fn read_any_json(filename: &str) { let content = std::fs::read_to_string(filename).expect("File not found"); let data: serde_json::Value = serde_json::from_str(&content).expect("JSON parsing error"); println!("{:#?}", &data); println!("--------"); let title = match data.get("title") { Some(val) => val.as_str().unwrap(), None => panic!("Field text does not exist"), }; println!("title: {title}"); let jobs = match data.get("jobs") { Some(val) => val.as_object().unwrap(), None => panic!("Field jobs does not exist"), }; println!("{:#?}", &jobs); for (key, value) in jobs.iter() { println!("key: {:?} value: {:?}", key, value); } println!("--------"); } fn read_struct_json(filename: &str) { let content = std::fs::read_to_string(filename).expect("File not found"); let data: Config = serde_json::from_str(&content).expect("JSON parsing error"); println!("data = {:?}", data); println!("title: {}", data.title); println!("{:?}", data.jobs.keys()); for (key, value) in data.jobs.iter() { println!("key: {:?} {:?}", key, value); } assert_eq!(data.title, "Sample file"); assert_eq!(data.jobs["test"].runs_on, Platform::ubuntu); assert_eq!(data.jobs["build"].runs_on, Platform::windows); }