camel_processor/data_format/
xml.rs1use camel_api::body::Body;
2use camel_api::data_format::DataFormat;
3use camel_api::error::CamelError;
4use camel_api::xml_convert::{json_to_xml, xml_to_json};
5
6pub struct XmlDataFormat;
7
8impl DataFormat for XmlDataFormat {
9 fn name(&self) -> &str {
10 "xml"
11 }
12
13 fn marshal(&self, body: Body) -> Result<Body, CamelError> {
14 match body {
15 Body::Json(v) => {
16 let xml = json_to_xml(&v)?;
17 Ok(Body::Text(xml))
18 }
19 Body::Text(_) => Ok(body),
20 Body::Stream(_) => Err(CamelError::TypeConversionFailed(
21 "cannot marshal Body::Stream — add 'stream_cache' or 'convert_body_to' before this step".to_string(),
22 )),
23 Body::Empty | Body::Bytes(_) => Err(CamelError::TypeConversionFailed(
24 "XmlDataFormat::marshal only supports Body::Json and Body::Text".to_string(),
25 )),
26 Body::Xml(_) => Err(CamelError::TypeConversionFailed(
27 "XmlDataFormat::marshal does not accept Body::Xml — use unmarshal to convert XML to JSON"
28 .to_string(),
29 )),
30 }
31 }
32
33 fn unmarshal(&self, body: Body) -> Result<Body, CamelError> {
34 match body {
35 Body::Json(_) => Ok(body),
36 Body::Text(s) => {
37 let v = xml_to_json(&s)?;
38 Ok(Body::Json(v))
39 }
40 Body::Bytes(b) => {
41 let s = String::from_utf8(b.to_vec()).map_err(|e| {
42 CamelError::TypeConversionFailed(format!(
43 "cannot unmarshal Body::Bytes as XML: {e}"
44 ))
45 })?;
46 let v = xml_to_json(&s)?;
47 Ok(Body::Json(v))
48 }
49 Body::Xml(s) => {
50 let v = xml_to_json(&s)?;
51 Ok(Body::Json(v))
52 }
53 Body::Stream(_) => Err(CamelError::TypeConversionFailed(
54 "cannot unmarshal Body::Stream directly — use UnmarshalService which auto-materializes"
55 .to_string(),
56 )),
57 Body::Empty => Err(CamelError::TypeConversionFailed(
58 "XmlDataFormat::unmarshal only supports Body::Json, Body::Text, Body::Bytes, and Body::Xml"
59 .to_string(),
60 )),
61 }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use bytes::Bytes;
69 use serde_json::json;
70
71 #[test]
72 fn test_name() {
73 assert_eq!(XmlDataFormat.name(), "xml");
74 }
75
76 #[test]
77 fn test_unmarshal_text_to_json() {
78 let body = Body::Text("<root><child>value</child></root>".to_string());
79 let result = XmlDataFormat.unmarshal(body).unwrap();
80 match result {
81 Body::Json(v) => assert_eq!(v["root"]["child"], json!("value")),
82 _ => panic!("expected Body::Json"),
83 }
84 }
85
86 #[test]
87 fn test_unmarshal_bytes_to_json() {
88 let body = Body::Bytes(Bytes::from_static(b"<root/>"));
89 let result = XmlDataFormat.unmarshal(body).unwrap();
90 match result {
91 Body::Json(v) => assert_eq!(v["root"], serde_json::Value::Null),
92 _ => panic!("expected Body::Json"),
93 }
94 }
95
96 #[test]
97 fn test_unmarshal_xml_body_to_json() {
98 let body = Body::Xml("<root><a>1</a></root>".to_string());
99 let result = XmlDataFormat.unmarshal(body).unwrap();
100 match result {
101 Body::Json(v) => assert_eq!(v["root"]["a"], json!("1")),
102 _ => panic!("expected Body::Json"),
103 }
104 }
105
106 #[test]
107 fn test_unmarshal_invalid_xml() {
108 let body = Body::Text("not xml".to_string());
109 let result = XmlDataFormat.unmarshal(body);
110 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
111 }
112
113 #[test]
114 fn test_unmarshal_json_noop() {
115 let body = Body::Json(json!({"x": 1}));
116 let result = XmlDataFormat.unmarshal(body).unwrap();
117 assert!(matches!(result, Body::Json(_)));
118 }
119
120 #[test]
121 fn test_unmarshal_empty_returns_error() {
122 let body = Body::Empty;
123 let result = XmlDataFormat.unmarshal(body);
124 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
125 }
126
127 #[test]
128 fn test_marshal_json_to_text() {
129 let body = Body::Json(json!({"root": {"name": "Alice"}}));
130 let result = XmlDataFormat.marshal(body).unwrap();
131 match result {
132 Body::Text(s) => {
133 assert!(s.contains("<root>"));
134 assert!(s.contains("<name>Alice</name>"));
135 }
136 _ => panic!("expected Body::Text"),
137 }
138 }
139
140 #[test]
141 fn test_marshal_text_noop() {
142 let body = Body::Text("already text".to_string());
143 let result = XmlDataFormat.marshal(body).unwrap();
144 assert_eq!(result, Body::Text("already text".to_string()));
145 }
146
147 #[test]
148 fn test_marshal_empty_returns_error() {
149 let body = Body::Empty;
150 let result = XmlDataFormat.marshal(body);
151 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
152 }
153
154 #[test]
155 fn test_marshal_xml_body_rejected() {
156 let body = Body::Xml("<root/>".to_string());
157 let result = XmlDataFormat.marshal(body);
158 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
159 }
160}