Десериализация нескольких полей JSON в один Ve c в serde - PullRequest
0 голосов
/ 05 августа 2020

Не могли бы вы помочь мне со следующей проблемой?

У меня есть JSON:

{
    "some_other_field": "value",
    "option1": "value1",
    "option2": "value2",
    [...]
    "option10": "value10",
}

Есть до X optionX полей, которые являются необязательными

Я хотел бы десериализовать его в структуру с одним Vec<String>, где индекс в векторе соответствует суффиксу в имени поля:

options[1] -> value of `option1`
options[10] -> value of `option10`

Вот моя структура:

struct Data {
    some_other_field: String,
    options: Vec<String>,
}

Я пробовал много вещей, в том числе написал собственный десериализатор, но не могу решить эту проблему: (

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 05 августа 2020

Вы можете создать массив строк, перебирая проанализированное значение, а затем передайте его в родительскую структуру.

use serde_json::{Result, Value};

fn main() -> Result<()> {
    let data = r#"
        {
          "some_other_field": "value",
          "option1": "value1",
          "option2": "value2",
          "option8": "value8",
          "option10": "value10"
        }"#;

    let v: Value = serde_json::from_str(data)?;

    let mut k = v
        .as_object()
        .unwrap()
        .iter()
        .filter(|(k, val)| k.contains("option") && val.as_str() != None)
        .map(|(k, vs)| {
            (
                k.replace("option", "").parse::<usize>().unwrap(),
                vs.as_str().unwrap().to_string(),
            )
        })
        .collect::<Vec<(usize, String)>>();

    k.sort();
    let mut result: Vec<String> = vec![];
    let mut it: usize = 0;
    let mut idx: usize = 0;
    let mut tidx: usize = 0;
    while idx < k.len() {
        tidx = k[idx].0;
        while it != tidx {
            result.push("".to_string());
            it += 1;
        }
        result.push(k[idx].to_owned().1);
        idx += 1;
        it += 1;
    }
    println!("{:?}", result);
    Ok(())
}

Вывод:

["", "value1", "value2", "", "", "", "", "", "value8", "", "value10"]
0 голосов
/ 05 августа 2020

Один из способов решить эту проблему - сериализовать данные JSON с помощью serde_json, а затем использовать временную карту для выбора этих значений. Я пропустил много проверок ошибок, но вот схема:

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

#[derive(Debug)]
struct Data {
    some_other_field: String,
    options: Vec<String>,
}

fn text_to_data(text: &str) -> Result<Data> {
    let prefix: &'static str = "option";

    // Deserialize JSON
    let value: Value = serde_json::from_str(text)?;
    let value_map = value.as_object().unwrap();

    // Filter keys for "option*", cut prefix, convert to integer and store it in a map
    let options_map: HashMap<usize, &str> = value_map.iter()
        .filter(|it| it.0.starts_with(prefix))
        .map(|it| (it.0[prefix.len()..].parse::<usize>().unwrap(), it.1.as_str().unwrap()))
        .collect();

    // Get the maximum of options
    let options_count = options_map.iter().map(|it| it.0).max().unwrap();

    // Collect values to a vector or use empty string as default
    let options: Vec<String> = (0..=*options_count)
        .map(|it| options_map.get(&it).unwrap_or(&"").to_string()).collect();

    // Also access other fields in JSON
    let some_other_field =
        value.get("some_other_field").unwrap().as_str().unwrap().to_string();

    Ok(Data { some_other_field, options })
}


fn main() {
    let data = r#"
        {
            "some_other_field": "value",
            "option1": "value1",
            "option2": "value2",
            "option10": "value10"
        }"#;

    let x = text_to_data(data);
    println!("{:?}", x);
}

Вывод:

Ok(Data { some_other_field: "value", options: ["", "value1", "value2", "", "", "", "", "", "", "", "value10"] })
...