use std::collections::BTreeMap;
use deser::Serialize;
use deser::de::Recording;
use deser_value::Value;
use deser_xml::{DeserializerConfig, Root, SerializerConfig, from_str, to_string};
const RESOLVE: DeserializerConfig = DeserializerConfig::builder()
.resolve_namespaces(true)
.build();
fn round_trip(config: &DeserializerConfig, input: &str) -> String {
let recording: Recording = config.from_str(input).unwrap();
to_string(&recording).unwrap()
}
#[test]
fn test_root_of_values() {
let input = r#"<feed id="1"><title>x</title><entry>a</entry><entry>b</entry></feed>"#;
let recording: Recording = from_str(input).unwrap();
assert_eq!(to_string(&recording).unwrap(), input);
let value: Value = from_str(input).unwrap();
assert_eq!(to_string(&value).unwrap(), input);
for input in ["<name>x</name>", "<empty/>", r#"<name lang="en">x</name>"#] {
assert_eq!(round_trip(&DeserializerConfig::new(), input), input);
}
assert_eq!(
SerializerConfig::builder()
.root("r")
.build()
.to_string(&recording)
.unwrap(),
input
);
let recording: Recording = from_str("<r><a>1</a></r>").unwrap();
assert_eq!(deser_json::to_string(&recording).unwrap(), r#"{"a":"1"}"#);
}
#[test]
fn test_namespaces_of_values() {
for input in [
r#"<feed xmlns="urn:atom"><title>x</title></feed>"#,
r#"<a:feed xmlns:a="urn:a" a:x="1"><a:t>x</a:t></a:feed>"#,
r#"<doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:x x.xsd"><a>1</a></doc>"#,
r#"<a:feed xmlns="urn:atom" xmlns:a="urn:a"><title>x</title><a:t>y</a:t></a:feed>"#,
] {
assert_eq!(round_trip(&DeserializerConfig::new(), input), input);
assert_eq!(round_trip(&RESOLVE, input), input);
}
const PREFIXED: DeserializerConfig = DeserializerConfig::new().namespaces(&[("x", "urn:a")]);
assert_eq!(
round_trip(
&PREFIXED,
r#"<a:feed xmlns:a="urn:a"><a:t>x</a:t></a:feed>"#
),
r#"<x:feed xmlns:x="urn:a"><x:t>x</x:t></x:feed>"#
);
}
#[test]
fn test_nested_namespaces() {
for input in [
r#"<r><a:t xmlns:a="urn:a">x</a:t></r>"#,
r#"<r><a:t xmlns:a="urn:a" a:x="1"><a:u>y</a:u></a:t></r>"#,
r#"<r><t xmlns="urn:a">1</t><t xmlns="urn:b">2</t></r>"#,
r#"<r><a:t xmlns:a="urn:a"/><a:t xmlns:a="urn:a"/></r>"#,
r#"<r xmlns:a="urn:a"><a:t><b xmlns:a="urn:b"><a:u>x</a:u></b></a:t></r>"#,
] {
assert_eq!(round_trip(&DeserializerConfig::new(), input), input);
assert_eq!(round_trip(&RESOLVE, input), input);
let value: Value = from_str(input).unwrap();
assert_eq!(to_string(&value).unwrap(), input);
}
let input = r#"<feed xmlns="urn:atom"><title>x</title><x xmlns="">1</x></feed>"#;
assert_eq!(round_trip(&DeserializerConfig::new(), input), input);
assert_eq!(round_trip(&RESOLVE, input), input);
let input = r#"<a:r xmlns:a="urn:a"><b xmlns:a="urn:b"><x>1</x></b></a:r>"#;
let recording: Recording = RESOLVE.from_str(input).unwrap();
let mut value: Value = RESOLVE.from_str(input).unwrap();
let b = value.as_map_mut().unwrap().get_mut("b").unwrap();
b.as_map_mut().unwrap().insert("{urn:a}y", "2");
assert_eq!(to_string(&recording).unwrap(), input);
assert_eq!(
to_string(&value).unwrap(),
r#"<a:r xmlns:a="urn:a" xmlns:ns0="urn:a"><b xmlns:a="urn:b"><x>1</x><ns0:y>2</ns0:y></b></a:r>"#
);
}
#[test]
fn test_deserialize_root() {
let doc: Root<BTreeMap<String, String>> = from_str(
r#"<feed xmlns="urn:atom" xmlns:dc="urn:dc"><dc:creator>Jane</dc:creator></feed>"#,
)
.unwrap();
assert_eq!(doc.name.as_deref(), Some("feed"));
assert_eq!(
doc.namespaces,
[
(String::new(), "urn:atom".to_string()),
("dc".to_string(), "urn:dc".to_string())
]
);
assert_eq!(doc.value["dc:creator"], "Jane");
let doc: Root<String> = RESOLVE.from_str(r#"<a:n xmlns:a="urn:a">x</a:n>"#).unwrap();
assert_eq!(doc.name.as_deref(), Some("{urn:a}n"));
assert_eq!(doc.value, "x");
let doc: Root<u32> = deser_json::from_str("42").unwrap();
assert_eq!(
doc,
Root {
name: None,
namespaces: vec![],
value: 42
}
);
}
#[test]
fn test_serialize_root() {
#[derive(Serialize)]
#[deser(rename = "point")]
struct Point {
#[deser(rename = "@x")]
x: i32,
}
assert_eq!(to_string(&Root::new("n", 42)).unwrap(), "<n>42</n>");
assert_eq!(
to_string(&Root::new("p", Point { x: 1 })).unwrap(),
r#"<p x="1"/>"#
);
let config = SerializerConfig::builder().root("r").build();
assert_eq!(
config.to_string(&Point { x: 1 }).unwrap(),
r#"<point x="1"/>"#
);
assert_eq!(config.to_string(&Root::new("n", 1)).unwrap(), "<n>1</n>");
let root = Root {
name: None,
namespaces: vec![("a".into(), "urn:a".into())],
value: Point { x: 1 },
};
assert_eq!(
to_string(&root).unwrap(),
r#"<point xmlns:a="urn:a" x="1"/>"#
);
let config = SerializerConfig::new().namespaces(&[("a", "urn:other"), ("b", "urn:b")]);
let root =
Root::new("{urn:a}doc", BTreeMap::from([("{urn:other}x", 1)])).with_namespace("a", "urn:a");
assert_eq!(
config.to_string(&root).unwrap(),
r#"<a:doc xmlns:a="urn:a" xmlns:b="urn:b" xmlns:ns0="urn:other"><ns0:x>1</ns0:x></a:doc>"#
);
for prefix in ["a:b", "1"] {
let root = Root::new("r", 1).with_namespace(prefix, "urn:a");
assert!(to_string(&root).is_err(), "{prefix}");
}
let value = BTreeMap::from([("a", Root::new("b", 1))]);
assert_eq!(
SerializerConfig::builder()
.root("r")
.build()
.to_string(&value)
.unwrap(),
"<r><a>1</a></r>"
);
}
#[test]
fn test_root_of_captured_values() {
let input = r#"<a:feed xmlns:a="urn:a"><a:t>x</a:t></a:feed>"#;
let doc: Root<Recording> = from_str(input).unwrap();
assert_eq!(doc.name.as_deref(), Some("a:feed"));
assert_eq!(to_string(&doc).unwrap(), input);
assert_eq!(
to_string(&doc.value).unwrap_err().message(),
"the name of the root element is unknown (see deser_xml::Root)"
);
let mut doc: Root<Value> = from_str(input).unwrap();
doc.name = Some("a:entry".into());
assert_eq!(
to_string(&doc).unwrap(),
r#"<a:entry xmlns:a="urn:a"><a:t>x</a:t></a:entry>"#
);
let recording: Recording = deser_json::from_str(r#"{"@a": 1, "b": [2, 3]}"#).unwrap();
assert_eq!(
to_string(&Root::new("r", recording)).unwrap(),
r#"<r a="1"><b>2</b><b>3</b></r>"#
);
}