解析嵌套的 JSON 对象
Parsing a nested JSON object
我正在尝试使用 Rust 中的 serde_json
解析具有以下松散格式的 JSON 文件:
{
"Source_n": {
"Destination_n": {
"distance": 2,
"connections": [
{
"color": "Any",
"locomotives": 0,
"tunnels": 0
}
]
}
...
其中 Source
和 Destination
可以是任意数量的键 (Link to full file)。
我创建了以下结构,试图反序列化 JSON:
#[derive(Debug, Deserialize)]
struct L0 {
routes: HashMap<String, L1>,
}
#[derive(Debug, Deserialize)]
struct L1 {
destination_city: HashMap<String, L2>,
}
#[derive(Debug, Deserialize)]
struct L2 {
distance: u8,
connections: Vec<L3>,
}
#[derive(Debug, Deserialize, Clone)]
struct L3 {
color: String,
locomotives: u8,
tunnels: u8,
}
当我尝试将 JSON 读取为 L0 对象时,我在这一行出现了恐慌:
let data: L0 = serde_json::from_str(&route_file_as_string).unwrap();
恐慌:
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/ticket-to-ride`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("missing field `routes`", line: 1889, column: 1)', src/route.rs:39:64
stack backtrace:
0: rust_begin_unwind
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/std/src/panicking.rs:517:5
1: core::panicking::panic_fmt
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/panicking.rs:101:14
2: core::result::unwrap_failed
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/result.rs:1617:5
3: core::result::Result<T,E>::unwrap
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/result.rs:1299:23
4: ticket_to_ride::route::route_file_to_L0
at ./src/route.rs:39:20
5: ticket_to_ride::route::routes_from_file
at ./src/route.rs:44:33
6: ticket_to_ride::main
at ./src/main.rs:6:5
7: core::ops::function::FnOnce::call_once
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ops/function.rs:227:5
我已经能够将 JSON 读取为 HashMap<String, Value>
对象,但每当我尝试开始在较低级别工作时,我都会收到错误消息。它似乎在寻找一个名为 routes
的键,但我实际上想要的只是一个嵌套的 HashMap,类似于您如何以嵌套方式在 Python 中读取 JSON。
关于如何进行的任何建议?我对这个库的尝试合理吗?
正如 Sven Marnach 在他们的评论中所说,添加 #[serde(flatten)]
以从使用键作为 JSON 字段的数据创建 HashMap:
#[derive(Debug, Deserialize)]
struct L0 {
#[serde(flatten)]
routes: HashMap<String, L1>,
}
#[derive(Debug, Deserialize)]
struct L1 {
#[serde(flatten)]
destination_city: HashMap<String, L2>,
}
解析引用 JSON 的功能代码如下。 demo
函数执行解析。
use serde::Deserialize;
use std::collections::HashMap;
use std::fs;
use std::clone::Clone;
#[derive(Debug, Deserialize)]
pub struct L1 {
#[serde(flatten)]
destination_city: HashMap<String, L2>,
}
#[derive(Debug, Deserialize)]
struct L2 {
distance: u8,
connections: Vec<L3>,
}
#[derive(Debug, Deserialize, Clone)]
struct L3 {
color: String,
locomotives: u8,
tunnels: u8,
}
fn route_file_to_hashmap(fpath: &str) -> HashMap<String, L1> {
let route_file_as_string = fs::read_to_string(fpath).expect("Unable to read file");
let data: HashMap<String, L1> = serde_json::from_str(&route_file_as_string).unwrap();
return data;
}
pub fn routes_from_file(fpath: &str) -> HashMap<String, L1> {
let route_file_as_map: HashMap<String, L1> = route_file_to_hashmap(fpath);
return route_file_as_map;
}
pub fn demo() {
let routes: HashMap<String, L1> = routes_from_file("usa.routes.json");
println!("---Cities---");
for (k, _) in &routes {
println!("{}", k);
}
let chicago: &HashMap<String, L2> = &routes.get("Chicago").unwrap().destination_city;
println!("---Destinations from Chicago---");
for (k, _) in chicago {
println!("{}", k);
}
let to_omaha: &L2 = chicago.get("Omaha").unwrap();
println!("---Data on Route to Omaha---");
println!("Distance: {}", to_omaha.distance);
print!("Connections: ");
for c in &to_omaha.connections {
println!("{} ", c.color);
}
}
我正在尝试使用 Rust 中的 serde_json
解析具有以下松散格式的 JSON 文件:
{
"Source_n": {
"Destination_n": {
"distance": 2,
"connections": [
{
"color": "Any",
"locomotives": 0,
"tunnels": 0
}
]
}
...
其中 Source
和 Destination
可以是任意数量的键 (Link to full file)。
我创建了以下结构,试图反序列化 JSON:
#[derive(Debug, Deserialize)]
struct L0 {
routes: HashMap<String, L1>,
}
#[derive(Debug, Deserialize)]
struct L1 {
destination_city: HashMap<String, L2>,
}
#[derive(Debug, Deserialize)]
struct L2 {
distance: u8,
connections: Vec<L3>,
}
#[derive(Debug, Deserialize, Clone)]
struct L3 {
color: String,
locomotives: u8,
tunnels: u8,
}
当我尝试将 JSON 读取为 L0 对象时,我在这一行出现了恐慌:
let data: L0 = serde_json::from_str(&route_file_as_string).unwrap();
恐慌:
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/ticket-to-ride`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("missing field `routes`", line: 1889, column: 1)', src/route.rs:39:64
stack backtrace:
0: rust_begin_unwind
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/std/src/panicking.rs:517:5
1: core::panicking::panic_fmt
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/panicking.rs:101:14
2: core::result::unwrap_failed
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/result.rs:1617:5
3: core::result::Result<T,E>::unwrap
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/result.rs:1299:23
4: ticket_to_ride::route::route_file_to_L0
at ./src/route.rs:39:20
5: ticket_to_ride::route::routes_from_file
at ./src/route.rs:44:33
6: ticket_to_ride::main
at ./src/main.rs:6:5
7: core::ops::function::FnOnce::call_once
at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ops/function.rs:227:5
我已经能够将 JSON 读取为 HashMap<String, Value>
对象,但每当我尝试开始在较低级别工作时,我都会收到错误消息。它似乎在寻找一个名为 routes
的键,但我实际上想要的只是一个嵌套的 HashMap,类似于您如何以嵌套方式在 Python 中读取 JSON。
关于如何进行的任何建议?我对这个库的尝试合理吗?
正如 Sven Marnach 在他们的评论中所说,添加 #[serde(flatten)]
以从使用键作为 JSON 字段的数据创建 HashMap:
#[derive(Debug, Deserialize)]
struct L0 {
#[serde(flatten)]
routes: HashMap<String, L1>,
}
#[derive(Debug, Deserialize)]
struct L1 {
#[serde(flatten)]
destination_city: HashMap<String, L2>,
}
解析引用 JSON 的功能代码如下。 demo
函数执行解析。
use serde::Deserialize;
use std::collections::HashMap;
use std::fs;
use std::clone::Clone;
#[derive(Debug, Deserialize)]
pub struct L1 {
#[serde(flatten)]
destination_city: HashMap<String, L2>,
}
#[derive(Debug, Deserialize)]
struct L2 {
distance: u8,
connections: Vec<L3>,
}
#[derive(Debug, Deserialize, Clone)]
struct L3 {
color: String,
locomotives: u8,
tunnels: u8,
}
fn route_file_to_hashmap(fpath: &str) -> HashMap<String, L1> {
let route_file_as_string = fs::read_to_string(fpath).expect("Unable to read file");
let data: HashMap<String, L1> = serde_json::from_str(&route_file_as_string).unwrap();
return data;
}
pub fn routes_from_file(fpath: &str) -> HashMap<String, L1> {
let route_file_as_map: HashMap<String, L1> = route_file_to_hashmap(fpath);
return route_file_as_map;
}
pub fn demo() {
let routes: HashMap<String, L1> = routes_from_file("usa.routes.json");
println!("---Cities---");
for (k, _) in &routes {
println!("{}", k);
}
let chicago: &HashMap<String, L2> = &routes.get("Chicago").unwrap().destination_city;
println!("---Destinations from Chicago---");
for (k, _) in chicago {
println!("{}", k);
}
let to_omaha: &L2 = chicago.get("Omaha").unwrap();
println!("---Data on Route to Omaha---");
println!("Distance: {}", to_omaha.distance);
print!("Connections: ");
for c in &to_omaha.connections {
println!("{} ", c.color);
}
}