如何在层次结构中迭代JSON对象?

6

我想要在嵌套的层次结构中打印每个联系人对象的name。由于联系人对象每次可能没有完全相同数量的字段以构建合适的结构,因此我该如何实现这一点?

extern crate serde_json;

use serde_json::{Error, Value};
use std::collections::HashMap;

fn untyped_example() -> Result<(), Error> {
    // Some JSON input data as a &str. Maybe this comes from the user.
    let data = r#"{
      "name":"John Doe",
      "age":43,
      "phones":[
        "+44 1234567",
        "+44 2345678"
      ],
      "contact":{
        "name":"Stefan",
        "age":23,
        "optionalfield":"dummy field",
        "phones":[
          "12123",
          "345346"
        ],
        "contact":{
          "name":"James",
          "age":34,
          "phones":[
            "23425",
            "98734"
          ]
        }
      }
    }"#;

    let mut d: HashMap<String, Value> = serde_json::from_str(&data)?;
    for (str, val) in d {
        println!("{}", str);
        if str == "contact" {
            d = serde_json::from_value(val)?;
        }
    }

    Ok(())
}

fn main() {
    untyped_example().unwrap();
}

我对Rust非常陌生,基本上是从JavaScript领域过来的。


1
你的“联系人”也有他们自己的联系人吗?“James”是“Stefan”的联系人,“Stefan”是“John Doe”的联系人? - Shepmaster
2个回答

2

我浏览了serde_json::value::Value枚举,找到了你需要的内容:

extern crate serde_json;
use serde_json::{Value};

fn main() {
    let data = r#"{
      "name":"John Doe",
      "age":43,
      "phones":[
        "+44 1234567",
        "+44 2345678"
      ],
      "contact":{
        "name":"Stefan",
        "age":23,
        "optionalfield":"dummy field",
        "phones":[
          "12123",
          "345346"
        ],
        "contact":{
          "name":"James",
          "age":34,
          "phones":[
            "23425",
            "98734"
          ]
        }
      }
    }"#;
    let data: Value = serde_json::from_str(data).unwrap();
    read_value(&data, "name");
}

fn read_value(value: &Value,  search_word: &str) {
    for val in value.as_object().unwrap(){
        let (key, v) = val;
        if key == "name" {
            println!("> name: {}",v);
        }
        if v.is_object() { // if it is an object, check recursively
            read_value(&v, search_word);
        }
    }
}

这个任务可以用非递归的方式完成,但我认为递归实现在代码上更简洁、更优雅。此外,对于这种任务来说,递归实现看起来更短。


1

可能每次都没有完全相同数量的字段来创建合适的结构

不清楚您为什么会这样想:

extern crate serde_json; // 1.0.24
#[macro_use]
extern crate serde_derive; // 1.0.70;

use serde_json::Error;

#[derive(Debug, Deserialize)]
struct Contact {
    name: String,
    contact: Option<Box<Contact>>,
}

impl Contact {
    fn print_names(&self) {
        println!("{}", self.name);

        let mut current = self;

        while let Some(ref c) = current.contact {
            println!("{}", c.name);

            current = &c;
        }
    }
}

fn main() -> Result<(), Error> {
    let data = r#"{
      "name":"John Doe",
      "contact":{
        "name":"Stefan",
        "contact":{
          "name":"James"
        }
      }
    }"#;

    let person: Contact = serde_json::from_str(data)?;
    person.print_names();

    Ok(())
}

我已从JSON中删除了额外的字段,以得到一个更小的示例,但如果它们存在,什么也不会改变。
另请参阅:
- 学习Rust太多链表 - 为什么递归结构类型在Rust中是非法的? - Rust和Serde JSON反序列化示例?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接