99

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Vikaton
  • 2,227
  • 3
  • 14
  • 23
  • It looks like you read the right page for parsing it. Did you see the [example](http://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html#parsing-a-str-to-json-and-reading-the-result) down the page that looks like exactly what you want? – squiguy May 17 '15 at 22:24
  • @squiguy Yeah I added `let obj = data.as_object().unwrap();` and got `thread '
    ' panicked at 'called `Option::unwrap()` on a `None` value', C:/bo t/slave/stable-dist-rustc-win-32/build/src/libcore\option.rs:362 }An unknown error occurred`
    – Vikaton May 17 '15 at 22:28

6 Answers6

92

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
42

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());
}
Vikaton
  • 2,227
  • 3
  • 14
  • 23
37

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");
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
tworec
  • 4,409
  • 2
  • 29
  • 34
  • An answer using serde_json is already present. Please [edit] this answer to more clearly show what is different and useful that warrants repeating. – Shepmaster Oct 24 '18 at 13:16
6

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);
}
semore_1267
  • 1,327
  • 2
  • 14
  • 29
  • 1
    An answer using serde_json is already present. Please [edit] *this* answer to more clearly show what is different and useful that warrants repeating. – Shepmaster Aug 16 '18 at 02:35
  • 1
    Unlike in other answer how to get the string from the file was not described. This is a full example of how to use serde to read from a separate file (foo.json) and take that string read_to_string and finally unwrap it. Also, the links to serde_json did not work nor did the example for serde_json::from_reader() work from the website. – Zargold Jan 16 '19 at 19:08
  • It doesn't work. `buff` does not live long enough borrowed value does not live long enough – Wiktor Kujawa Sep 02 '23 at 23:30
5

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();
}
netlemon
  • 964
  • 8
  • 22
-2

Rust comes with an elegant native-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());
}
Sunding Wei
  • 1,803
  • 17
  • 12
  • Nice but it does not answer the question. This allows you to paste json into your code but not to parse an external file. – Simson Jan 31 '23 at 08:37