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 作为一个字符串,我可以稍后绑定。
(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 可能无效,因此您无论如何都需要一些错误处理。
无论如何,这已经成为一个很长的答案,希望它对某人有用。
我正在尝试将嵌套的 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 作为一个字符串,我可以稍后绑定。
(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 可能无效,因此您无论如何都需要一些错误处理。
无论如何,这已经成为一个很长的答案,希望它对某人有用。