Skip to main content

mx20022_parse/
ser.rs

1//! Serialization of ISO 20022 message types to XML.
2//!
3//! Thin wrappers around [`quick_xml::se`] that translate errors into
4//! [`ParseError`].
5//!
6//! # Examples
7//!
8//! ```no_run
9//! # use mx20022_parse::ser::to_string;
10//! # use mx20022_model::generated::head::BusinessApplicationHeaderV04;
11//! # let hdr: BusinessApplicationHeaderV04 = unimplemented!();
12//! let xml = to_string(&hdr).unwrap();
13//! ```
14
15use serde::Serialize;
16
17use crate::ParseError;
18
19/// XML declaration prepended when using [`to_string_with_declaration`].
20const XML_DECLARATION: &str = r#"<?xml version="1.0" encoding="UTF-8"?>"#;
21
22/// Serialize an ISO 20022 message type to an XML string.
23///
24/// The root element name is derived from the struct name (or `#[serde(rename)]`).
25/// No XML declaration is prepended; use [`to_string_with_declaration`] if needed.
26///
27/// # Errors
28///
29/// Returns [`ParseError::Serialize`] if the value cannot be serialized.
30pub fn to_string<T: Serialize>(value: &T) -> Result<String, ParseError> {
31    quick_xml::se::to_string(value).map_err(ParseError::Serialize)
32}
33
34/// Serialize an ISO 20022 message type to an XML string with an XML declaration.
35///
36/// Prepends `<?xml version="1.0" encoding="UTF-8"?>` before the XML body.
37///
38/// # Errors
39///
40/// Returns [`ParseError::Serialize`] if the value cannot be serialized.
41pub fn to_string_with_declaration<T: Serialize>(value: &T) -> Result<String, ParseError> {
42    let body = quick_xml::se::to_string(value).map_err(ParseError::Serialize)?;
43    Ok(format!("{XML_DECLARATION}{body}"))
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn to_string_with_declaration_prepends_declaration() {
52        #[derive(serde::Serialize)]
53        struct Msg {
54            value: u32,
55        }
56
57        let result = to_string_with_declaration(&Msg { value: 42 }).unwrap();
58        assert!(
59            result.starts_with(r#"<?xml version="1.0" encoding="UTF-8"?>"#),
60            "expected XML declaration at start, got: {result}"
61        );
62        assert!(
63            result.contains("<value>42</value>"),
64            "expected body in output"
65        );
66    }
67
68    #[test]
69    fn to_string_no_declaration() {
70        #[derive(serde::Serialize)]
71        struct Msg {
72            value: u32,
73        }
74
75        let result = to_string(&Msg { value: 7 }).unwrap();
76        assert!(
77            !result.starts_with("<?xml"),
78            "to_string must not include XML declaration"
79        );
80        assert!(result.contains("<value>7</value>"));
81    }
82}