rustxml-deserializationserde

How to deserialize a string representation of boolean in XML


I'm trying to parse xml response containing boolean representation as strings into bool type in a custom structure. A similar question was mentioned here for json files. And I get a runtime error that I suspect is just like the one mentioned here, but I don't know how I can fix it.

MRE:

[package]
name = "test_range_2"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0.147", features = ["derive"] }
serde-xml-rs = "0.6.0"
// main.rs
use serde::Deserialize;

fn deserialize_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
    D: serde::de::Deserializer<'de>,
{
    let s: &str = serde::de::Deserialize::deserialize(deserializer)?;

    match s {
        "TRUE" => Ok(true),
        "FALSE" => Ok(false),
        _ => Err(serde::de::Error::unknown_variant(s, &["TRUE", "FALSE"])),
    }
}

#[allow(dead_code)]
#[derive(Debug, Deserialize)]
struct Custom {
    #[serde(deserialize_with = "deserialize_bool")]
    tag1: bool,
    #[serde(deserialize_with = "deserialize_bool")]
    tag2: bool,
}

fn main() {
    let xml_raw = r#"
    <?xml version="1.0"?>
    <Custom>
        <tag1>TRUE</tag1>
        <tag2>FALSE</tag2>
    </Custom>
    "#;

    let events = serde_xml_rs::from_str::<Custom>(xml_raw)
        .expect("unable to deserialize xml into Custom struct");

    println!("{:#?}", events);
}

Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/test_range_2`
thread 'main' panicked at 'unable to deserialize xml into Custom struct: Custom { field: "invalid type: string \"TRUE\", expected a borrowed string" }', src/main.rs:35:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Related links:


Solution

  • The error message here is useful

    "invalid type: string "TRUE", expected a borrowed string"

    You are trying to deserialize the string value as a &str instead of a String. This might be weirdness in the serde_xml_rs library but changing it to String lets it run as expected.

    fn deserialize_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        let s: String = serde::de::Deserialize::deserialize(deserializer)?;
    
        match s.as_str() { // note change here
            "TRUE" => Ok(true),
            "FALSE" => Ok(false),
            _ => Err(serde::de::Error::unknown_variant(&s, &["TRUE", "FALSE"])), // and borrow here
        }
    }