如何在Rust中使用serde解析这个JSON文件?

huangapple go评论66阅读模式
英文:

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:

{
&quot;comment&quot;: [&quot;some comments&quot;],
&quot;data&quot;: [
    [&quot;name&quot;, &quot;line 1&quot;],
    [&quot;name&quot;, [&quot;line 1&quot;, &quot;line 2&quot;]],
    ......
    [&quot;name&quot;, &quot;line 1&quot;]
]
//(The line where the error is coming)

}

I made structures like this:

#[derive(Debug, Deserialize)]
struct my_data {
    comment: String,
    data: Vec&lt;sub_data&gt;,
}
#[derive(Debug, Deserialize)]
struct sub_data {
    name: String, 
    pattern: Vec&lt;String&gt;,
}

Then I tried this code but got an error:

Error(&quot;missing field `Comment`&quot;, line: 1381, column: 1)&#39;,

Code:

pub fn read_json () {
    let path = &quot;./src/my_file.json&quot;;
    let data = fs::read_to_string(path).expect(&quot;Unable to read file&quot;);
    let obj: my_data = serde_json::from_str(&amp;data).expect(&quot;Unable to parse&quot;);
    println!(&quot;{:?}&quot;, 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&lt;String&gt;,
    data: Vec&lt;SubData&gt;,
}

#[derive(Debug, Deserialize)]
struct SubData {
    name: String, 
    pattern: StringOrList,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum StringOrList {
    String(String),
    List(Vec&lt;String&gt;),
}

huangapple
  • 本文由 发表于 2023年2月24日 15:07:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75553500.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定