JSON Parsing

serde_json is the most commonly used crate for JSON Parsing. simd_json is optimized for performance.

Parse JSON with serde_json

serde_json serde_json-crates.io serde_json-github serde_json-lib.rs cat-parser-implementations cat-no-std cat-encoding

serde_json offers a JSON serialization file format.

use serde::Deserialize;
use serde::Serialize;
use serde_json::Result;
use serde_json::Value;

/// Represents a user with a name, age, and a list of phone numbers.
#[derive(Deserialize, Serialize, Debug)]
struct User {
    name: String,
    age: u8,
    phones: Vec<String>,
}

/// Demonstrates parsing and serializing JSON data using the `serde_json` crate.
///
/// This function parses a JSON string into a `Value` enum and a custom `User`
/// struct, then serializes the `User` struct back into a JSON string.
fn main() -> Result<()> {
    let json_str = r#"
    {
        "name": "John Doe",
        "age": 42,
        "phones": [
            "+1 123456789",
            "+1 234567890"
        ]
    }
    "#;

    // 1. Parse the JSON string into a `Value` enum.
    // The `Value` enum can represent any valid JSON value.
    let parsed: Value = serde_json::from_str(json_str)?;
    // There are also `from_slice` for parsing from a byte slice `&[u8]`
    // and `from_reader` for parsing from any `io::Read` type,
    // such as a `File` or a TCP stream.

    // 2. Access parts of the data by indexing with square brackets.
    // The result of square bracket indexing is a borrow, so the type is
    // `&Value`.
    let name = parsed["name"].as_str().unwrap();
    let age = parsed["age"].as_i64().unwrap();
    let phones = parsed["phones"].as_array().unwrap();

    println!("Name: {}", name);
    println!("Age: {}", age);
    println!("Phones: {:?}", phones);

    // 3. Parse the JSON string into a custom `User` struct.
    // The `User` struct must implement the `Deserialize` trait.
    let user: User = serde_json::from_str(json_str)?;
    println!("{:?}", user);

    // 4. Serialize the `User` struct back into a JSON string.
    let u = serde_json::to_string(&user)?;
    println!("{u}");
    // There are also `serde_json::to_vec`, which serializes to a `Vec<u8>`,
    // and `serde_json::to_writer`, which serializes to any `io::Write`,
    // such as a `File` or a TCP stream.

    Ok(())
}

Parse JSON with json5

json5 json5-crates.io json5-github json5-lib.rs

json5 is a Rust JSON5 serializer and deserializer which speaks serde.

//! This example demonstrates how to parse JSON5 data using the `json5` crate.
//!
//! [JSON5](https://json5.org) is a superset of JSON that allows for more human-friendly syntax,
//! such as comments, unquoted keys, and trailing commas.
//! It aims to be easier to write and maintain by hand (e.g. for config files).
//! It is not intended to be used for machine-to-machine communication.
use serde_json::Value;

fn main() {
    let json5_str = r#"{
        // Comments are allowed
        unquoted: 'and you can use single quotes',
        trailingComma: ['in arrays', 'like', 'this', ],
        hexadecimal: 0xDEADbeef,
        infinity: Infinity,
        nan: NaN,
        nested: {
            pi: 3.141592653,
        },
        'quoted key': true, // Quoted keys are allowed
        "backwardsCompatible": "with JSON",
    }"#;

    // Parse the JSON5 string into a `serde_json::Value`.
    match json5::from_str::<Value>(json5_str) {
        Ok(value) => {
            println!("Parsed JSON5: {:#?}", value);

            if let Some(nested) = value.get("nested") {
                if let Some(pi) = nested.get("pi") {
                    println!("Pi: {}", pi);
                }
            }

            if let Some(hex) = value.get("hexadecimal") {
                println!("Hex: {}", hex);
            }

            if let Some(inf) = value.get("infinity") {
                println!("Infinity: {}", inf);
            }

            if let Some(nan) = value.get("nan") {
                println!("NaN: {}", nan);
            }

            if let Some(unquoted) = value.get("unquoted") {
                println!("Unquoted: {}", unquoted);
            }

            if let Some(quoted_key) = value.get("quoted key") {
                println!("Quoted Key: {}", quoted_key);
            }
        }
        Err(e) => {
            eprintln!("Error parsing JSON5: {}", e);
        }
    }
}

Parse JSON with simd-json

simd-json simd-json-crates.io simd-json-github simd-json-lib.rs

simd-json is a high-performance JSON parser based on a port of simdjson.

//! Example of using the `simd-json` crate for parsing and manipulating JSON
//! data.
//!
//! `simd-json` is a Rust port of the extremely fast simdjson c++ library with
//! `serde` compatibility. For best performance, use `mimalloc` or `jemalloc`
//! instead of the system allocator used by default.
//!
//! Example of using `mimalloc`:
//! ```rust
//! use mimalloc::MiMalloc;
//!
//! #[global_allocator]
//! static GLOBAL: MiMalloc = MiMalloc;
//! ```
use simd_json::OwnedValue;
use simd_json::derived::ValueObjectAccess;
use simd_json::derived::ValueObjectAccessAsArray;
use simd_json::derived::ValueObjectAccessAsScalar;
use simd_json::prelude::*;

fn main() {
    let mut json_string = br#"
    {
        "name": "Alice",
        "age": 30,
        "city": "New York",
        "numbers": [1, 2, 3, 4, 5],
        "nested": {
            "value": true
        }
    }
    "#
    .to_vec();

    // Parse the JSON string into a `BorrowedValue`.
    // `BorrowedValue` is designed for read-only access and avoids unnecessary
    // copying, making it very fast.
    match simd_json::to_borrowed_value(&mut json_string) {
        Ok(json) => {
            println!("Parsed JSON: {:?}", json);

            // Access values using `ValueAccess` traits.
            if let Some(name) = json.get_str("name") {
                println!("Name: {}", name);
            }

            if let Some(age) = json.get_u64("age") {
                println!("Age: {}", age);
            }

            if let Some(city) = json.get_str("city") {
                println!("City: {}", city);
            }

            if let Some(numbers) = json.get_array("numbers") {
                println!("Numbers: {:?}", numbers);
            }

            if let Some(nested) = json.get("nested") {
                if let Some(nested_value) = nested.get_bool("value") {
                    println!("Nested Value: {}", nested_value);
                }
            }
        }
        Err(e) => {
            eprintln!("Error parsing JSON: {}", e);
        }
    }

    // Example using `OwnedValue` (for modifications).
    // This is slower then the `BorrowedValue` as a tradeoff for getting rid of
    // lifetimes.
    let mut owned_json: OwnedValue =
        simd_json::to_owned_value(&mut json_string).unwrap();

    if let Some(name) = owned_json.get_mut("name") {
        *name = OwnedValue::from("Bob");
    }

    println!("Modified Owned JSON: {}", owned_json);
}