How do I parse a JSON File?

I have this so far in my goal to Parse this JSON data in Rust:

extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::fs::File;
use std::io::copy;
use std::io::stdout;


fn main() {
let mut file = File::open("text.json").unwrap();
let mut stdout = stdout();
let mut str = &copy(&mut file, &mut stdout).unwrap().to_string();
let data = Json::from_str(str).unwrap();
}

and text.json is

{
"FirstName": "John",
"LastName": "Doe",
"Age": 43,
"Address": {
"Street": "Downing Street 10",
"City": "London",
"Country": "Great Britain"
},
"PhoneNumbers": [
"+44 1234567",
"+44 2345678"
]
}

What should be my next step into parsing it? My primary goal is to get JSON data like this, and parse a key from it, like Age.

61632 次浏览

Solved by the many helpful members of the Rust community:

extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::fs::File;
use std::io::Read;


fn main() {
let mut file = File::open("text.json").unwrap();
let mut data = String::new();
file.read_to_string(&mut data).unwrap();


let json = Json::from_str(&data).unwrap();
println!("{}", json.find_path(&["Address", "Street"]).unwrap());
}

Serde is the preferred JSON serialization provider. You can read the JSON text from a file a number of ways. Once you have it as a string, use serde_json::from_str:

fn main() {
let the_file = r#"{
"FirstName": "John",
"LastName": "Doe",
"Age": 43,
"Address": {
"Street": "Downing Street 10",
"City": "London",
"Country": "Great Britain"
},
"PhoneNumbers": [
"+44 1234567",
"+44 2345678"
]
}"#;


let json: serde_json::Value =
serde_json::from_str(the_file).expect("JSON was not well-formatted");
}

Cargo.toml:

[dependencies]
serde = { version = "1.0.104", features = ["derive"] }
serde_json = "1.0.48"

You could even use something like serde_json::from_reader to read directly from an opened File.

Serde can be used for formats other than JSON and it can serialize and deserialize to a custom struct instead of an arbitrary collection:

use serde::Deserialize;


#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Person {
first_name: String,
last_name: String,
age: u8,
address: Address,
phone_numbers: Vec<String>,
}


#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
struct Address {
street: String,
city: String,
country: String,
}


fn main() {
let the_file = /* ... */;


let person: Person = serde_json::from_str(the_file).expect("JSON was not well-formatted");
println!("{:?}", person)
}

Check the Serde website for more details.

Upvoted the accepted answer (as it helps), but just adding my answer, using the widely used serde_json crate referenced by @FrickeFresh

Assuming your foo.json is

{
"name": "Jane",
"age": 11
}

Implementation would look something like

extern crate serde;
extern crate json_serde;
#[macro_use] extern crate json_derive;
use std::fs::File;
use std::io::Read;


#[derive(Serialize, Deserialize)]
struct Foo {
name: String,
age: u32,
}


fn main() {
let mut file = File::open("foo.json").unwrap();
let mut buff = String::new();
file.read_to_string(&mut buff).unwrap();


let foo: Foo = serde_json::from_str(&buff).unwrap();
println!("Name: {}", foo.name);
}

There is a brief and complete example of how to read JSON from file in serde_json::de::from_reader docs.

Here is a short snippet for:

  • reading a file
  • parsing its contents as a JSON
  • and extracting a field with the desired key

Enjoy:

let file = fs::File::open("text.json")
.expect("file should open read only");
let json: serde_json::Value = serde_json::from_reader(file)
.expect("file should be proper JSON");
let first_name = json.get("FirstName")
.expect("file should have FirstName key");

You can extract this functionality into a utility. As per their docs, this might be a valid piece of software

use std::{
fs::File,
io::BufReader,
path::Path,
error::Error
};


use serde_json::Value;


fn read_payload_from_file<P: AsRef<Path>>(path: P) -> Result<Value, Box<dyn Error>> {
// Open file in RO mode with buffer
let file = File::open(path)?;
let reader = BufReader::new(file);


// Read the JSON contents of the file
let u = serde_json::from_reader(reader)?;


Ok(u)
}


fn main() {
let payload: Value =
read_payload_from_file("./config/payload.json").unwrap();
}

Rust comes with an elegant native-json (wsd::json) crate, which declares native JSON object with Rust, and native acccess to members.

Example of native-json

use native_json::json;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};


fn main()
{
let mut json = json!{
name: "native json",
style: {
color: "red",
size: 12,
bold: true,
range: null
},
array: [5,4,3,2,1],
vector: vec![1,2,3,4,5],
hashmap: HashMap::from([ ("a", 1), ("b", 2), ("c", 3) ]);,
students: [
{name: "John", age: 18},
{name: "Jack", age: 21},
],
};


// Native access
json.style.size += 1;
json.students[0].age += 2;


// Debug
println!("{:#?}", t);


// Stringify
let text = serde_json::to_string_pretty(&json).unwrap();
println!("{}", text);
}

native-json way

use wsd::json::*;


fn main() {
// Declare as native JSON object
let mut john = json!{
name: "John Doe",
age: 43,
phones: [
"+44 1234567",
"+44 2345678"
]
};


// Native access to member
john.age += 1;


println!("first phone number: {}", john.phones[0]);


// Convert to a string of JSON and print it out
println!("{}", stringify(&john, 4));
}

serde_json way

use serde_json::json;


fn main() {
// The type of `john` is `serde_json::Value`
let john = json!({
"name": "John Doe",
"age": 43,
"phones": [
"+44 1234567",
"+44 2345678"
]
});


println!("first phone number: {}", john["phones"][0]);


// Convert to a string of JSON and print it out
println!("{}", john.to_string());
}