从JSON数组中选择键的子集

时间:2015-08-09 19:04:33

标签: json parsing rust serde

我正在尝试解析一个像这样吐出输出的JSON API:

{
  "message": "success", 
  "number": 6, 
  "people": [
    {
      "craft": "ISS", 
      "name": "Gennady Padalka"
    }, 
    {
      "craft": "ISS", 
      "name": "Mikhail Kornienko"
    }, 
    {
      "craft": "ISS", 
      "name": "Scott Kelly"
    }, 
    {
      "craft": "ISS", 
      "name": "Oleg Kononenko"
    }, 
    {
      "craft": "ISS", 
      "name": "Kimiya Yui"
    }, 
    {
      "craft": "ISS", 
      "name": "Kjell Lindgren"
    }
  ]
}

来源:http://api.open-notify.org/astros.json

我正在使用serde,并且到目前为止已设法提出以下代码:

extern crate curl;
extern crate serde_json;

use curl::http;
use std::str;
use serde_json::{from_str};

fn main() {
    // Fetch the data
    let response = http::handle()
       .get("http://api.open-notify.org/astros.json")
       .exec().unwrap();

     // Get the raw UTF-8 bytes
     let raw_bytes = response.get_body();
     // Convert them to a &str
     let string_body: &str = str::from_utf8(&raw_bytes).unwrap();

     // Get the JSON into a 'Value' Rust type
     let json: serde_json::Value = serde_json::from_str(&string_body).unwrap();

     // Get the number of people in space
     let num_of_ppl: i64 = json.find_path(&["number"]).unwrap().as_i64().unwrap();
     println!("There are {} people on the ISS at the moment, they are: ", num_of_ppl);

     // Get the astronauts
     // Returns a 'Value' vector of people
     let ppl_value_space = json.find_path(&["people"]).unwrap();
     println!("{:?}", ppl_value_space);
}

现在,ppl_value_space正如预期的那样让我这样:

[{"craft":"ISS","name":"Gennady Padalka"}, {"craft":"ISS","name":"Mikhail Kornienko"}, {"craft":"ISS","name":"Scott Kelly"}, {"craft":"ISS","name":"Oleg Kononenko"}, {"craft":"ISS","name":"Kimiya Yui"}, {"craft":"ISS","name":"Kjell Lindgren"}]

但是,我想转到"name"键,基本上有类似的东西:

[{"name":"Gennady Padalka"}, {"name":"Mikhail Kornienko"}, {"name":"Scott Kelly"}, {"name":"Oleg Kononenko"}, {"name":"Kimiya Yui"}, {"name":"Kjell Lindgren"}]

这样才能得到目前在太空中的宇航员的名字。

如果没有"name",如何在"people"内获得"craft"

尝试到达name,如此:

ppl_value_space[0].find_path(&["name"]).unwrap();

但它以恐慌结束,这基本上意味着关键是None,因为我unwrap()Option<T>

1 个答案:

答案 0 :(得分:2)

这对我有用:

if let &Value::Array(ref people) = ppl_value_space {
    let names = people.iter().filter_map(|person| person.find_path(&["name"]));
    for name in names {
        println!("{:?}", name);
    }
}

由于serde_json::Valueenum,因此它可以是许多不同类型的值。而数组只是其中之一,它可能是其他东西,如字符串或数字。我们希望它是一个数组,但Rust强迫我们考虑其他情况。

在这种情况下,我们会使用 if-let 语句忽略除Value::Array之外的所有类型。当条件为真时,我们得到对包含数组的引用。

我们遍历数组中的每个项目,并在其中找到名称对象。 filter_map用于忽略None值,但您可能希望执行不同的操作。

每个值都打印出来,但您也可以collect将它们转换为新的Vec或更令人兴奋的内容。