rust 如何使用serde_json获取JSON文件中的一个特定项而不派生结构体?

u5rb5r59  于 2023-04-21  发布在  其他
关注(0)|答案(3)|浏览(277)

我有一个复杂的JSON文件,我想只提取其中的一个值。我可以定义所有的struct,并在所有的Deserialize上派生Deserialize,但我想只写一点手动代码来提取那个值。坦率地说,Serde documentation让我感到困惑。
我的JSON内容具有以下布局:

{
  "data": [
    {
      "hostname": "a hostname"
    }
  ]
}

我通过进入data来查找导航到的值,然后获取数组的第一个元素,并获取hostname的值。
在Haskell中,我会这样做:

newtype Host = Host Text

instance FromJSON Host where
    parseJSON (Object o) = (return . Host) <=< (.: "hostname") <=< (fmap (!! 0) . parseJSON) <=< (.: "data") $ o
    parseJSON _ = mzero

Serde的等价物是什么?

bq9c1y66

bq9c1y661#

serde_jsonserde_json::Value提供了通用JSON值的类型:

use serde_json::Value;

// input variable
let input: &str = "{...}";

// parse into generic JSON value
let root: Value = serde_json::from_str(input)?;

// access element using .get()
let hostname: Option<&str> = root.get("data")
    .and_then(|value| value.get(0))
    .and_then(|value| value.get("hostname"))
    .and_then(|value| value.as_str());

// hostname is Some(string_value) if .data[0].hostname is a string,
// and None if it was not found
println!("hostname = {:?}", hostname); // = Some("a hostname")

full playground example

y1aodyip

y1aodyip2#

如果你可以在值丢失或格式错误的情况下返回Value::Null,我会使用Index语法([...])。如果你想以不同的方式处理丢失/格式错误的情况,请使用get方法:

fn main() {
    let json_value = serde_json::json!({
      "data": [
        {
          "hostname": "a hostname"
        }
      ]
    });

    let host = &json_value["data"][0]["hostname"];
    println!("Host: {:?}", host);
}

您也可以通过pointer使用JSON Pointer

let host = json_value.pointer("/data/0/hostname");
println!("Host: {:?}", host);
4zcjmb1e

4zcjmb1e3#

我会把扁平的建筑

use serde::{Serialize, Deserialize};
use serde_json::Value;

#[derive(Serialize, Deserialize)]
struct Payload {
    data: Vec<Data>,

    #[serde(flatten)]
    _: HashMap<String, Value>,
}

#[derive(Serialize, Deserialize)]
struct Data {
    hostname: String,

    #[serde(flatten)]
    _: HashMap<String, Value>,
}

let payload: Payload = serde_json::from_str(your_string)?;
assert_eq!(payload.data.0.hostname, "a hostname");

相关问题