【发布时间】:2026-01-23 10:50:02
【问题描述】:
我正在尝试使用 serde 解析以下 JSON 格式
{
"threads": [
{
"md": [
{
"type": "PARAGRAPH",
"value": [
{
"type": "PLAIN_TEXT",
"value": "Plain text msg "
},
{
"type": "INLINE_CODE",
"value": {
"type": "PLAIN_TEXT",
"value": "print('hello')"
}
},
{
"type": "ITALIC",
"value": [
{
"type": "PLAIN_TEXT",
"value": "italic text"
}
]
}
]
}
]
}
]
}
代码如下:
use std::fmt;
use std::marker::PhantomData;
use std::str::FromStr;
use serde::{de, Deserialize, Deserializer};
use serde::de::{MapAccess, SeqAccess, Visitor};
use void::Void;
use std::collections::BTreeMap as Map;
impl FromStr for SubValue {
type Err = Void;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(SubValue{
value: s.to_string(),
value_type: None
})
}
}
#[derive(Deserialize, Debug)]
pub struct SubValue {
value: String,
#[serde(rename = "type")]
value_type: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Value {
#[serde(rename = "type")]
value_type: String,
#[serde(deserialize_with = "string_or_struct")]
value: SubValue,
}
#[derive(Deserialize, Debug)]
pub struct MessageData {
#[serde(rename = "type")]
pub msg_type: String,
pub value: Vec<Value>,
}
#[derive(Deserialize, Debug)]
pub struct Thread {
pub md: Vec<MessageData>
}
#[derive(Deserialize, Debug)]
pub struct ThreadList {
pub threads: Vec<Thread>,
}
fn string_or_struct<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: Deserialize<'de> + FromStr<Err=Void>,
D: Deserializer<'de>,
{
struct StringOrStruct<T>(PhantomData<fn() -> T>);
impl<'de, T> Visitor<'de> for StringOrStruct<T>
where
T: Deserialize<'de> + FromStr<Err=Void>,
{
type Value = T;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string or map or list")
}
fn visit_str<E>(self, value: &str) -> Result<T, E>
where
E: de::Error,
{
Ok(FromStr::from_str(value).unwrap())
}
fn visit_seq<M>(self, seq: M) -> Result<T, M::Error>
where
M: SeqAccess<'de>,
{
Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))
}
fn visit_map<M>(self, map: M) -> Result<T, M::Error>
where M: MapAccess<'de>,
{
Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))
}
}
deserializer.deserialize_any(StringOrStruct(PhantomData))
}
fn main() {
let data =
"{\n\
\"threads\": [\n\
{\n\
\"md\": [\n\
{\n\
\"type\": \"PARAGRAPH\",\n\
\"value\": [\n\
{\n\
\"type\": \"PLAIN_TEXT\",\n\
\"value\": \"Plain text msg \"\n\
},\n\
{\n\
\"type\": \"INLINE_CODE\",\n\
\"value\": {\n\
\"type\": \"PLAIN_TEXT\",\n\
\"value\": \"print('hello')\"\n\
}\n\
},\n\
{\n\
\"type\": \"ITALIC\",\n\
\"value\": [\n\
{\n\
\"type\": \"PLAIN_TEXT\",\n\
\"value\": \"italic text\"\n\
}\n\
]\n\
}\n\
]\n\
}\n\
]\n\
}\n\
]\n\
}\n";
let v: ThreadList = serde_json::from_str(data).expect("Failed to parse");
for x in v.threads {
for md in x.md{
for val in md.value {
println!("{}", val.value.value)
}
}
}
}
最大的问题是我无法解析italic 下面的列表。
如果可能的话,我想展平列表并将值结构替换为值“斜体文本”,但它会因thread 'main' panicked at 'Failed to parse: Error("invalid type: map, expected a string", line: 22, column: 0)', src/main.rs:129:51 而崩溃
我正在尝试使用的 API 是火箭聊天获取线程 api https://developer.rocket.chat/reference/api/rest-api/endpoints/team-collaboration-endpoints/chat-endpoints/getthreadslist
【问题讨论】:
-
你在找类似playground的东西吗?
-
#[serde(serialize_with = "...")]是要走的路。另见github.com/serde-rs/serde/issues/889 -
#[serde(serialize_with = "...")]是我在示例中的内容,但我不知道如何处理该结构可以包含字符串、结构或向量。