提问人:mike rodent 提问时间:10/5/2023 最后编辑:mike rodent 更新时间:10/6/2023 访问量:62
反序列化 reqwest 提供的这种嵌套 JSON 结构
Deserialising this kind of nested JSON structure delivered by reqwest
问:
有人可能会指出这一点的重复。但我搜索过。关于这个主题有很多问题,但我似乎没有一个真正有帮助。
我交付的 JSON(来自 Elasticsearch)的结构是这样的:
当我去的时候:
let json_hashmap: HashMap<String, Value> = serde_json::from_str(&text).unwrap();
我明白了:
{
"hits": Object {
"hits": Array [
Object {
"_id": String("Ybgt6ooBpXznUptX4lR2"),
"_index": String("booby"),
"_score": Number(1.0),
... (other keys)
],
... (multiple other hit-hit Objects in the Array)
],
... (other keys)
}
"key2": String("my arbitrary string value"),
"key3": Number(1.0),
... (other keys)
}
这并不是说命中“字典”的键和嵌套数组是不可预测的。我可以为这些热门词典设计一个。但是,我怎样才能真正获得命中数组呢?struct
因为可以看出,0 级字典(外部字典)有一个键,该键解码为包含内部-内部字典数组(“级别 2”)的内部字典(“级别 1”)。
但是 0 级字典有除“命中”之外的键,这些键可以解码为其他值。事实上,1 级词典也可能有“命中”以外的键。
有没有办法规定“级别 0”(外部)字典中的一个特定键解码为,而该字典中的一个特定键解码为?HashMap<String, Value>
Vec<MyStruct>
注意:如果我去,我可以访问一些对象
let outer_hits = &json_hasmap["hits"];
let inner_hits = &outer_hits["hits"];
打印此文件显示:{:#?}
Array [
Object {
"_id": String("Ybgt6ooBpXznUptX4lR2"),
"_index": String("booby"),
"_score": Number(1.0),
"_source": Object {
"docx_id": Number(14),
"last_modif_ms": Number(1596958203000),
"ldoc_type": String("docx_doc"),
"path": String("D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-03.docx"),
},
},
Object {
...
...但是,例如,虽然这被称为类型,但我的尝试不会编译:我得到“ ^^^ 方法未找到 ”。奇怪的“数组”。我怎样才能提取更有用的东西?Array
inner_hits.len()
&Value
text
一开始是:
{
"_scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDnF1ZXJ5VGhlbkZldGNoBxZQcGUxbjhnQ1RzU0M1bG1ZR05od1VBAAAAAAAAASAWbkU3ck5YUTNSazZlazJtUXctSklWQRZQcGUxbjhnQ1RzU0M1bG1ZR05od1VBAAAAAAAAASEWbkU3ck5YUTNSazZlazJtUXctSklWQRZQcGUxbjhnQ1RzU0M1bG1ZR05od1VBAAAAAAAAASIWbkU3ck5YUTNSazZlazJtUXctSklWQRZQcGUxbjhnQ1RzU0M1bG1ZR05od1VBAAAAAAAAASMWbkU3ck5YUTNSazZlazJtUXctSklWQRZQcGUxbjhnQ1RzU0M1bG1ZR05od1VBAAAAAAAAASQWbkU3ck5YUTNSazZlazJtUXctSklWQRZQcGUxbjhnQ1RzU0M1bG1ZR05od1VBAAAAAAAAASUWbkU3ck5YUTNSazZlazJtUXctSklWQRZQcGUxbjhnQ1RzU0M1bG1ZR05od1VBAAAAAAAAASYWbkU3ck5YUTNSazZlazJtUXctSklWQQ==",
"took": 3,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 3,
"failed": 0
},
"hits": {
"total": {
"value": 5303,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "booby",
"_id": "Ybgt6ooBpXznUptX4lR2",
"_score": 1,
"_source": {
"docx_id": 14,
"last_modif_ms": 1596958203000,
"ldoc_type": "docx_doc",
"path": "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-03.docx"
}
},
{
"_index": "booby",
"_id": "jLgt6ooBpXznUptX4lSG",
"_score": 1,
"_source": {
"docx_id": 12,
"last_modif_ms": 1596958248000,
"ldoc_type": "docx_doc",
"path": "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-01.docx"
}
},
{
"_index": "booby",
"_id": "1bgt6ooBpXznUptX4lSX",
"_score": 1,
"_source": {
"docx_id": 20,
"last_modif_ms": 1596958053000,
"ldoc_type": "docx_doc",
"path": "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-09.docx"
}
},
{
"_index": "booby",
"_id": "7rgt6ooBpXznUptX4lSm",
"_score": 1,
"_source": {
"docx_id": 21,
"last_modif_ms": 1596958032000,
"ldoc_type": "docx_doc",
"path": "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-10.docx"
}
},
{
"_index": "booby",
"_id": "_rgt6ooBpXznUptX4lS2",
"_score": 1,
"_source": {
"docx_id": 22,
"last_modif_ms": 1596957990000,
"ldoc_type": "docx_doc",
"path": "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-11.docx"
}
}
]
}
}
答:
要从 serde_json::Value
中提取可行的类型(等),您可以对其进行模式匹配或使用辅助方法(例如)。Vec
HashMap
as_X()
as_array().unwrap().len()
但是,使用 serde 总是最好使用类型化反序列化而不是泛型 .访问更容易,反序列化更快。Value
评论
as_X
as_object
serde_json.from_value()
match x { serde_json::Value::Array(x) =>
if let serde_json::Value::Array(x) = x
最好对自己的类型进行建模,以反映预期的 JSON 结构,而不是使用泛型 .您可以通过实现 serde::D eserialize
来实现这一点。像这样的东西(只实现了一些字段):Value
use serde::Deserialize;
use serde_json::json;
#[derive(Debug, Deserialize)]
struct Response {
// _scroll_id
// took
// timed_out
// _shards
hits: HitsResponse,
}
#[derive(Debug, Deserialize)]
struct HitsResponse {
// total
// max_score
hits: Vec<Hit>,
}
#[derive(Debug, Deserialize)]
struct Hit {
// _index
_id: String,
// _score
_source: HitSource,
}
#[derive(Debug, Deserialize)]
struct HitSource {
// docx_id
// last_modif_ms,
// ldoc_type
path: String,
}
将 JSON 解析为上述内容将产生以下结果:Response
let response: Response = serde_json::from_str(&text).unwrap();
Response {
hits: HitsResponse {
hits: [
Hit {
_id: "Ybgt6ooBpXznUptX4lR2",
_source: HitSource {
path: "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-03.docx",
},
},
Hit {
_id: "jLgt6ooBpXznUptX4lSG",
_source: HitSource {
path: "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-01.docx",
},
},
Hit {
_id: "1bgt6ooBpXznUptX4lSX",
_source: HitSource {
path: "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-09.docx",
},
},
Hit {
_id: "7rgt6ooBpXznUptX4lSm",
_source: HitSource {
path: "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-10.docx",
},
},
Hit {
_id: "_rgt6ooBpXznUptX4lS2",
_source: HitSource {
path: "D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-11.docx",
},
},
],
},
}
如果您使用的是 reqwest,您可以直接使用 .json
而不是 + (通过启用其功能)。.text
.bytes
serde_json
"json"
评论
serde_json::from_value
struct
作为一个几乎没有尿布的 Rust 新手(可能很明显),考虑到对这个问题感兴趣的 2 个人的知识,我犹豫是否要提供这个解决方案。但这似乎有效。我不知道这是否是一个好的解决方案。
#[derive(Debug, Serialize, Deserialize)]
struct HitSource {
docx_id: usize,
last_modif_ms: usize,
ldoc_type: String,
path: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct Hit {
_id: String,
_index: String,
_score: f64,
_source: HitSource,
}
...
let hits_dict = &json_hashmap["hits"];
let hits_array = &hits_dict["hits"].as_array().unwrap();
...
for hit in *hits_array {
/*
NB each hit looks like this:
{
"_id": String("1bgt6ooBpXznUptX4lSX"),
"_index": String("booby"),
"_score": Number(1.0),
"_source": Object {
"docx_id": Number(20),
"last_modif_ms": Number(1596958053000),
"ldoc_type": String("docx_doc"),
"path": String("D:\\My Documents\\doc\\IT_Diary\\IT Diary $UPD 2018-09.docx"),
},
}
*/
let hit_result: Result<Hit, _> = serde_json::from_value(hit.clone());
info!("{:#?}", hit_result);
}
...这确实提供了 非错误 ,这似乎没问题。Result<Hit, _>
然而,kmdreko 的解决方案似乎是规范的解决方案:他的解决方案的关键是,在任何这些字典/地图中找到的任何键都不能被解释为所需的结构,都会被忽略:在所示的情况下,诸如“_scroll_id”、“taken”、“timed_out”、“_shards”等键。struct
我发现,如果我试图取消(他的外部字典/地图)并改用,这会引起一个错误......因为其他键,其值不能解释为 .如果所有人都可以,似乎可以工作。struct Response
struct
HashMap<String, HitsResponse>
HitsResponse
评论
serde_json::Value
text
json