英文:
How to parse this JSON file in Rust using serde?
问题
#[derive(Debug, Deserialize)]
struct my_data {
comment: Vec<String>,
data: Vec<sub_data>,
}
#[derive(Debug, Deserialize)]
struct sub_data {
name: String,
pattern: Vec<String>,
}
英文:
I am new to Rust. I am trying to parse a JSON file and store the data as objects in rust.
This is how the JSON File looks:
{
"comment": ["some comments"],
"data": [
["name", "line 1"],
["name", ["line 1", "line 2"]],
......
["name", "line 1"]
]
//(The line where the error is coming)
}
I made structures like this:
#[derive(Debug, Deserialize)]
struct my_data {
comment: String,
data: Vec<sub_data>,
}
#[derive(Debug, Deserialize)]
struct sub_data {
name: String,
pattern: Vec<String>,
}
Then I tried this code but got an error:
Error("missing field `Comment`", line: 1381, column: 1)',
Code:
pub fn read_json () {
let path = "./src/my_file.json";
let data = fs::read_to_string(path).expect("Unable to read file");
let obj: my_data = serde_json::from_str(&data).expect("Unable to parse");
println!("{:?}", obj);
return
}
Can someone help fix this?
答案1
得分: 3
首先,你的 JSON 不符合 PascalCase 命名规范。该属性告诉 serde 应该查找 "Comment" 和 "Data",而不是原始名称。Serde(默认情况下)会跳过所有其他键,并告诉你它没有找到任何名为 "Comment" 的键。JSON 可能是 camelCase,但由于所有键都是单词,我将保持它没有重命名属性。你可以查看容器属性文档自行决定。
其次,你没有正确地表示 JSON 数组在你的 Rust 类型中。由 SubData
表示的数组是可以的,因为 serde 会假定它们是结构体成员,按顺序排列,但由 SubData.pattern
表示的数组可以是数组,也可以是单个字符串,因此你无法直接将其反序列化为单一类型。这就是非标记枚举 StringOrList
处理的情况。如果你希望始终将其作为 Vec
处理,你可以使用deserialize_with 属性或serde_with
crate。
#[derive(Debug, Deserialize)]
struct MyData {
comment: Vec<String>,
data: Vec<SubData>,
}
#[derive(Debug, Deserialize)]
struct SubData {
name: String,
pattern: StringOrList,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum StringOrList {
String(String),
List(Vec<String>),
}
英文:
First of all, your JSON is not in PascalCase. That attribute tells serde to look for "Comment" and "Data" instead of the original names. Serde (by default) skips all the other keys and is letting you know it didn't find any called "Comment". The JSON might be camelCase, but since all the keys are single words, I'll just leave it without a rename attribute. You can check out the container attributes documentation for yourself to decide.
Second, you aren't representing the JSON arrays properly in your rust types. The arrays that are represented by SubData
are fine since serde will assume they're the struct members in order, but the array represented by SubData.pattern
is either an array or a single string, so you can't deserialize it directly to a single type. That's what the untagged enum StringOrList
is handling. If you want to make this always a Vec
, you can use the deserialize_with
attribute or the serde_with
crate.
#[derive(Debug, Deserialize)]
struct MyData {
comment: Vec<String>,
data: Vec<SubData>,
}
#[derive(Debug, Deserialize)]
struct SubData {
name: String,
pattern: StringOrList,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum StringOrList {
String(String),
List(Vec<String>),
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论