Как получить один конкретный элемент в файле JSON с помощью serde_json без создания структур?

У меня есть сложный файл JSON, и я хотел бы извлечь из него только одно значение. Я мог бы определить все struct и получить Deserialize для всех из них, но я хотел бы просто написать небольшой ручной код, чтобы извлечь это одно значение. Откровенно говоря, документация Serde меня просто смутила.

Мой контент 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

Какой эквивалент для Серде?


person Listerone    schedule 23.05.2019    source источник
comment
Эта ссылка предназначена для пользователей, которые хотят реализовать десериализатор / анализатор формата. Это должно быть то, что вам нужно.   -  person chpio    schedule 23.05.2019
comment
github.com/serde-rs/json#operating-on- untyped-json-values ​​   -  person turbulencetoo    schedule 23.05.2019


Ответы (3)


serde_json предоставляет типы для общих значений JSON с serde_json::Value:

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")

(полный пример игровой площадки)

person Frxstrem    schedule 23.05.2019

Если вы хотите запаниковать, если значение отсутствует или имеет неправильный формат, я бы использовал Index синтаксис ([...]). Если вы хотите обработать отсутствующий / неправильно сформированный случай, используйте get метод:

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

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

Вы также можете использовать указатель JSON через _ 5_:

let host = json_value.pointer("/data/0/hostname");
println!("Host: {:?}", host);
person Shepmaster    schedule 24.05.2019

Я бы связал плоские структуры

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");
person gustavodiazjaimes    schedule 24.05.2019