1#![forbid(unsafe_code)]
2
3mod decoders;
4mod errors;
5mod frames;
6
7use crate::frames::AttributesWriter;
8use decoders::decode_text;
9pub use errors::XmlToJsonError;
10use quick_xml::Reader;
11use quick_xml::events::Event;
12use std::io::{BufRead, BufReader, Read, Write};
13
14static CHILDREN_KEY: &str = "#c";
15static TEXT_NODE_KEY: &str = "#t";
16static MB: usize = 1024 * 1024;
17
18pub fn xml_to_json<R: Read, W: Write>(reader: R, out: W) -> Result<(), XmlToJsonError> {
60 xml_to_json_from_bufread(BufReader::new(reader), out)
61}
62
63pub fn xml_to_json_from_bufread<R: BufRead, W: Write>(
77 reader: R,
78 out: W,
79) -> Result<(), XmlToJsonError> {
80 let mut writer = std::io::BufWriter::with_capacity(MB * 2, out);
81 let mut xml = Reader::from_reader(reader);
82 xml.config_mut().trim_text(true);
83 let mut buf = Vec::with_capacity(256);
84 let mut stack: Vec<frames::Element> = Vec::with_capacity(16);
85 let mut spare_text_buf = String::new();
86
87 loop {
88 match (xml.read_event_into(&mut buf)?, stack.last_mut()) {
89 (Event::Start(e), None) => {
93 let text_buf = std::mem::take(&mut spare_text_buf);
94 let mut frame = frames::Element::new_and_open(&e, &xml, &mut writer, text_buf)?;
95 frame.process_element_attributes(&e, &xml, &mut writer)?;
96
97 stack.push(frame);
98 }
99
100 (Event::Empty(e), None) => {
102 let mut frame = frames::EmptyNode::new_and_open(&e, &xml, &mut writer)?;
103 frame.process_element_attributes(&e, &xml, &mut writer)?;
104 frame.close(&mut writer)?;
105
106 writer.flush()?;
107 return Ok(());
108 }
109
110 (Event::Start(e), Some(parent)) => {
114 parent.begin_child(&mut writer)?;
115
116 let text_buf = std::mem::take(&mut spare_text_buf);
117 let mut frame = frames::Element::new_and_open(&e, &xml, &mut writer, text_buf)?;
118 frame.process_element_attributes(&e, &xml, &mut writer)?;
119
120 stack.push(frame);
121 }
122
123 (Event::Empty(e), Some(parent)) => {
125 parent.begin_child(&mut writer)?;
126
127 let mut frame = frames::EmptyNode::new_and_open(&e, &xml, &mut writer)?;
128 frame.process_element_attributes(&e, &xml, &mut writer)?;
129 frame.close(&mut writer)?;
130 }
131
132 (Event::Text(t), Some(frame)) => {
134 let text = decode_text(&xml, &t)?;
135 frame.push_text(&text);
136 }
137
138 (Event::End(_), _) => {
140 if let Some(mut frame) = stack.pop() {
141 frame.close(&mut writer)?;
142 spare_text_buf = frame.take_text_buf();
143
144 if stack.is_empty() {
146 writer.flush()?;
147 return Ok(());
148 }
149 }
150 }
151
152 (Event::Eof, _) => break,
153 _ => {}
154 }
155
156 buf.clear();
157 }
158
159 Err(XmlToJsonError::InvalidXML)
160}
161
162#[cfg(test)]
163mod tests {
164
165 #[test]
166 fn test_nested_structure() {
167 let xml = r#"
168 <root>
169 <child1 attr1="value1">
170 <subchild>Text 1</subchild>
171 <subchild>Text 2</subchild>
172 <subchild>Text 3</subchild>
173 </child1>
174 <child2 attr2="value2" />
175 <child1 attr2="value2" attr3="value3" attr1="value1">
176 <subchild>Text 2</subchild>
177 <subchild>Text 1</subchild>
178 <subchild>Text 3</subchild>
179 </child1>
180 </root>
181 "#;
182
183 let expected_json = serde_json::json!({
184 "root": {
185 "#c": [
186 {
187 "child1": {
188 "@attr1": "value1",
189 "#c": [
190 {
191 "subchild": {
192 "#t": "Text 1"
193 }
194 },
195 {
196 "subchild": {
197 "#t": "Text 2"
198 }
199 },
200 {
201 "subchild": {
202 "#t": "Text 3"
203 }
204 },
205 ]
206 }
207 },
208 {
209 "child2": {
210 "@attr2": "value2"
211 }
212 },
213 {
214 "child1": {
215 "@attr3": "value3",
216 "@attr2": "value2",
217 "@attr1": "value1",
218 "#c": [
219 {
220 "subchild": {
221 "#t": "Text 2"
222 }
223 },
224 {
225 "subchild": {
226 "#t": "Text 1"
227 }
228 },
229 {
230 "subchild": {
231 "#t": "Text 3"
232 }
233 },
234 ]
235 }
236 },
237 ]
238 }
239 });
240
241 assert_eq!(expected_json, convert_xml_to_json(xml));
242 }
243
244 #[test]
245 fn test_basic_xml_to_json() {
246 let xml = r#"<users count="3">
247 <user age="40">Jane Doe</user>
248 <user age="42">John Doe</user>
249 <user age="12">Jim Doe</user>
250</users>"#;
251
252 let expected_json = serde_json::json!({
253 "users": {
254 "@count": "3",
255 "#c": [
256 {
257 "user": {
258 "@age": "40",
259 "#t": "Jane Doe"
260 }
261 },
262 {
263 "user": {
264 "@age": "42",
265 "#t": "John Doe"
266 }
267 },
268 {
269 "user": {
270 "@age": "12",
271 "#t": "Jim Doe"
272 }
273 }
274 ]
275 }
276 });
277
278 assert_eq!(expected_json, convert_xml_to_json(xml));
279 }
280
281 #[test]
282 fn test_single_element_with_text() {
283 let xml = "<name>John Doe</name>";
284 let expected_json = serde_json::json!({
285 "name": {
286 "#t": "John Doe"
287 }
288 });
289
290 assert_eq!(expected_json, convert_xml_to_json(xml));
291 }
292
293 #[test]
294 fn test_element_with_attributes_only() {
295 let xml = r#"<div class="container" id="main"></div>"#;
296 let expected_json = serde_json::json!({
297 "div": {
298 "@class": "container",
299 "@id": "main"
300 }
301 });
302
303 assert_eq!(expected_json, convert_xml_to_json(xml));
304 }
305
306 #[test]
307 fn test_nested_elements() {
308 let xml = r#"<root><parent id="1"><child>Value</child></parent></root>"#;
309 let expected_json = serde_json::json!({
310 "root": {
311 "#c": [
312 {
313 "parent": {
314 "@id": "1",
315 "#c": [
316 { "child": { "#t": "Value" } }
317 ]
318 }
319 }
320 ]
321 }
322 });
323
324 assert_eq!(expected_json, convert_xml_to_json(xml));
325 }
326
327 #[test]
328 fn test_empty_xml() {
329 assert!(super::xml_to_json(b"".as_slice(), Vec::new()).is_err());
330 }
331
332 #[test]
333 fn test_malformed_xml() {
334 assert!(super::xml_to_json(b"<root><unclosed>".as_slice(), Vec::new()).is_err());
335 }
336
337 #[test]
338 fn test_empty_nodes() {
339 let xml = "<main><br /></main>";
340 let expected_json = serde_json::json!({
341 "main": {
342 "#c": [
343 { "br": {}}
344 ]
345 }
346 });
347
348 assert_eq!(expected_json, convert_xml_to_json(xml));
349 }
350
351 #[test]
352 fn test_empty_node_at_root() {
353 let xml = "<br />";
354 let expected_json = serde_json::json!({ "br": {} });
355
356 assert_eq!(expected_json, convert_xml_to_json(xml));
357 }
358
359 #[test]
360 fn test_empty_node_at_root_with_attributes() {
361 let xml = r#"<br id="5" />"#;
362 let expected_json = serde_json::json!({ "br": { "@id": "5" } });
363
364 assert_eq!(expected_json, convert_xml_to_json(xml));
365 }
366
367 fn convert_xml_to_json(xml: &str) -> serde_json::Value {
368 let mut output = Vec::new();
369 super::xml_to_json(xml.as_bytes(), &mut output).unwrap();
370
371 serde_json::from_slice(&output).unwrap()
372 }
373}