serde 可以使用平面键值对反序列化 XML 吗?

Can serde deserialize XML with flat key value pairs?

我正在使用 serde-xml-rs 箱子。我有 XML,格式如下:

<data>
   <key>version</key>
   <int>4</int>
   <key>name</key>
   <string>John</string>
</data>

是否可以将其解析为这样的结构?

enum Node {
  #[serde(rename="int")]
  Int(u32),
  #[serde(rename="string")]
  String(String),
}
struct Data {
  // what serde attributes to use???
  version: Node,
  name: Node,
}

我只是设法将其解析为 Vec 个元组:

#[serde(rename = "$value")]
data: Vec<(String, Node)>,

据我所知,使用 Deserialize derive 宏无法完成您想做的事情。但是,您仍然可以实现您的目标:Serde 允许您 manually implement Deserialize 在派生宏不够强大的情况下。

如果您的代码需要高性能,您可能希望完全手动实现 Deserialize;否则,您也可以像上面那样先反序列化为元组,然后从中构建 Data 结构。这会更容易,因为您不需要直接与 Deserializer 交互,但由于中间数据表示,性能可能不如完全手动执行。

下面是一个利用中间元组表示的解决方案。

#[derive(serde::Deserialize, Debug)]
enum Node {
  #[serde(rename="int")]
  Int(u32),
  #[serde(rename="string")]
  String(String),
}
#[derive(Debug)]
struct Data {
  version: Node,
  name: Node,
}

impl<'de> serde::Deserialize<'de> for Data {
    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        use serde::de::Error;
        #[derive(serde::Deserialize, Debug)]
        struct IntermediateResult {
            #[serde(rename = "$value")]
            data: Vec<(String, Node)>,
        }

        // first, deserialize to the tuple via the macro generated Serialize implementation
        let intermediate_result: IntermediateResult = IntermediateResult::deserialize(deserializer)?;

        // find the keys we are looking for and save the values
        let mut version: Option<Node> = None;
        let mut name: Option<Node> = None;
        for key_value_pair in intermediate_result.data {
            let value_to_assign: &mut Option<Node> = match &*key_value_pair.0 {
                "version" => &mut version,
                "name" => &mut name,
                _ => {
                    // handle unknown <key> – either ignore it or return an error; I am going to ignore it
                    continue;
                }
            };
            *value_to_assign = Some(key_value_pair.1);
        }

        // if the required keys are missing, fail
        if version.is_none() {
            return Err(D::Error::custom("Did not find a <key> with content \"version\""));
        }
        if name.is_none() {
            return Err(D::Error::custom("Did not find a <key> with content \"name\""));
        }

        // otherwise, build Data struct
        Ok(Data {
            version: version.unwrap(),
            name: name.unwrap()
        })
    }
}

fn main() {
    let xml = r###"
        <data>
            <key>version</key>
            <int>4</int>
            <key>name</key>
            <string>John</string>
        </data>
   "###;
   
   let data: Data = serde_xml_rs::from_str(xml).unwrap();
   
   println!("{:?}", data);
}