Rust:将嵌套的 json 字符串序列化为 BTree<string,string>

Rust: Serializing a nested json stirng to a BTree<string,string>

我正在尝试将嵌套的 json 序列化为 BTree。 我将根据需要使用此集合的特定元素绑定到不同的结构。

JSON

{
    "data": "some_data",
    "key": "some_key",
    "nestedValue": {
        "timestamp": "0",
        "d1": "d1",
        "d2": "d2",
        "time": 0,
        "secindaryNestedValue": [{
                "d3": "test1",
                "d4": "test2"
            },
            {
                "d3": "test3",
                "d4": "test4"
            }
        ]
    },
    "timestamp": 0
}

我正在尝试将其序列化如下:

    let input: BTreeMap<String, String> = serde_json::from_str(INPUT).unwrap();
    println!("input -> {:?}",input);

我想得到如下输出:

B树项

Key             Value
data            some_data
key             some_key
nested_value    "{\"d1\":\"d1\",\"d2\":\"d2\",\"time\":0,\"secindaryNestedValue\":[{\"d3\":\"test1\",\"d4\":\"test2\"},{\"d3\":\"test3\",\"d4\":\"test4\"}]}"  
timestamp        0

我这样做是为了让我的嵌套 json 尽可能通用。

在后续操作中,我将使用 serde 将嵌套的 json 绑定到一个结构,如下所示使用结构 :

use serde_derive::Deserialize;
use serde_derive::Serialize;

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Root {
    pub data: String,
    pub key: String,
    pub nested_value: NestedValue,
    pub timestamp: i64,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NestedValue {
    pub timestamp: String,
    pub d1: String,
    pub d2: String,
    pub time: i64,
    pub secindary_nested_value: Vec<SecindaryNestedValue>,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SecindaryNestedValue {
    pub d3: String,
    pub d4: String,
}

我想稍后使用嵌套值, 将 json 字符串转换为 json 并将其绑定到类似的结构。

接受关于不使用 BTree 和更好的东西的建议,但我的用例要求我将内部嵌套的 jsons 作为一个字符串,我可以稍后绑定。

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4afbad3da5584bc67c9e70ae08f41cee

(2 个月后可能对 OP 没有用,但会为其他读者提供一些意见。)

我强烈怀疑您不想要 BTreeMap。这些主要用于排序,但是这些 JSON key-value 对不是您想要按键排序的东西。您可以尝试 HashMap<String, String>,但我再次怀疑这不是您真正想要的。对你的问题最接近合理的答案可能是使用 serde_json::Value,这是一个可以匹配任何有效 JSON 的通用类型。它被实现为

pub enum Value {
    Null,
    Bool(bool),
    Number(Number),
    String(String),
    Array(Vec<Value>),
    Object(Map<String, Value>),
}

所以这个 JSON 将反序列化为 Object,您可以使用包含的地图来做任何您需要的事情。如果您真的想将嵌套值放回字符串,请使用 serde_json::to_string 在任何必要的位置将其转换回。您随后可以使用 serde_json::from_value.

Value 转换为更具体的类型,例如 Root

但是我会注意到,根据我的经验,使用 Value 很少是最好的方法。我只在 API 集成时使用它,发送一些任意 JSON 作为某些数据的一部分,随后要求将相同的 JSON 作为另一个请求的一部分发回.您的确切要求并不完全清楚,但我会尽力猜测您真正想要的是什么:

  • 要序列化(Rust 到 JSON,这是在问题中指定的,但可能不是你真正的意思),你显示的结构应该很好地转换为 JSON 格式用 serde_json::to_string 指定。根据问题的其余部分,您似乎有一些更复杂的要求,这可能意味着需要更改这些要求,但是原理是正确的。

  • 要反序列化(JSON 到 Rust),这取决于您获取的数据。如果您知道数据以给定的格式出现,您可以将其直接反序列化为您定义的 Root 类型,并且嵌套值将正确构建为适当的类型。如果您需要以某种方式修改数据,我强烈建议您对反序列化类型而不是字符串进行修改。即使您想用作为 JSON 字符串获得的其他数据替换它的某些部分,最好反序列化该数据(可能是 NestedValue 或其他类型)并使用这些 Rust类型。这比尝试编辑 JSON 字符串要可靠得多。如果您需要将部分数据作为 JSON 呈现给外部用户或服务,您可以再次将其序列化。

  • 如果您不确定数据是否会以您编写的格式出现(您的部分问题表明您需要更多泛型类型,也许正因为如此?),您有基于它可能是什么的几个选项。如果可能缺少某些值,您可以使用 Option 作为反序列化类型:例如。如果可能缺少 nestedValue,请在 Root 结构中使用 pub nested_value: Option<NestedValue>。如果它可以遵循其他一些已知模式,则可以使用 enum 来匹配它们:例如

#[derive(Debug, Deserialize)]
#[serde(untagged)] // This tells serde to figure out from the type structure rather than the name.
pub enum RootEnum {
    Root {
        data: String,
        key: String,
        nested_value: NestedValue, // This can be used as it was.
        timestamp: i64,
    }
    SomeOtherType {
        foo: Bar
    }
}

如果这样做,您可能需要一个 match 块来确定如何使用数据。如果您真的不知道这些数据可能是什么样子,则需要使用 Value 对其进行反序列化。但是,那时我怀疑您无论如何都无法使用数据,因此您可能应该尝试反序列化为您知道的类型,并在不匹配时对收到的错误执行适当的操作。由于 JSON 可能无效,因此您无论如何都需要一些错误处理。

无论如何,这已经成为一个很长的答案,希望它对某人有用。