xml_disassembler/parsers/
parse_to_xml_object.rs1use crate::parsers::{
4 extract_xml_declaration_from_raw, extract_xmlns_from_raw, parse_xml_from_str,
5};
6use crate::types::XmlElement;
7use serde_json::Value;
8use tokio::fs;
9
10pub async fn parse_to_xml_object(file_path: &str) -> Option<XmlElement> {
11 if file_path.to_lowercase().ends_with(".xml") {
12 let content = fs::read_to_string(file_path).await.ok()?;
13 let mut parsed = parse_xml_from_str(&content, file_path)?;
14 if let Some(obj) = parsed.as_object_mut() {
15 if let Some(decl) = extract_xml_declaration_from_raw(&content) {
17 obj.insert("?xml".to_string(), decl);
18 }
19 if let Some(xmlns) = extract_xmlns_from_raw(&content) {
21 let root_key = obj.keys().find(|k| *k != "?xml")?.clone();
22 if let Some(root_val) = obj.get_mut(&root_key) {
23 if let Some(root_obj) = root_val.as_object_mut() {
24 if !root_obj.contains_key("@xmlns") {
25 root_obj.insert("@xmlns".to_string(), Value::String(xmlns));
26 }
27 }
28 }
29 }
30 }
31 return Some(parsed);
32 }
33
34 let content = fs::read_to_string(file_path).await.ok()?;
35
36 if file_path.to_lowercase().ends_with(".yaml") || file_path.to_lowercase().ends_with(".yml") {
37 return serde_yaml::from_str(&content).ok();
38 }
39
40 if file_path.to_lowercase().ends_with(".json5") {
41 return json5::from_str(&content).ok();
42 }
43
44 if file_path.to_lowercase().ends_with(".json") {
45 return serde_json::from_str(&content).ok();
46 }
47
48 None
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[tokio::test]
56 async fn parse_to_xml_object_json() {
57 let dir = tempfile::tempdir().unwrap();
58 let path = dir.path().join("test.json");
59 std::fs::write(&path, r#"{"root":{"a":1}}"#).unwrap();
60 let out = parse_to_xml_object(path.to_str().unwrap()).await;
61 assert!(out.is_some());
62 let obj = out.unwrap();
63 assert!(obj.get("root").is_some());
64 }
65
66 #[tokio::test]
67 async fn parse_to_xml_object_yaml() {
68 let dir = tempfile::tempdir().unwrap();
69 let path = dir.path().join("test.yaml");
70 std::fs::write(&path, "root:\n a: 1\n").unwrap();
71 let out = parse_to_xml_object(path.to_str().unwrap()).await;
72 assert!(out.is_some());
73 }
74
75 #[tokio::test]
76 async fn parse_to_xml_object_yml_extension() {
77 let dir = tempfile::tempdir().unwrap();
78 let path = dir.path().join("test.yml");
79 std::fs::write(&path, "root: {}").unwrap();
80 let out = parse_to_xml_object(path.to_str().unwrap()).await;
81 assert!(out.is_some());
82 }
83
84 #[tokio::test]
85 async fn parse_to_xml_object_json5() {
86 let dir = tempfile::tempdir().unwrap();
87 let path = dir.path().join("test.json5");
88 std::fs::write(&path, "{ root: { a: 1 } }").unwrap();
89 let out = parse_to_xml_object(path.to_str().unwrap()).await;
90 assert!(out.is_some());
91 }
92
93 #[tokio::test]
94 async fn parse_to_xml_object_unsupported_returns_none() {
95 let dir = tempfile::tempdir().unwrap();
96 let path = dir.path().join("test.txt");
97 std::fs::write(&path, "not xml").unwrap();
98 let out = parse_to_xml_object(path.to_str().unwrap()).await;
99 assert!(out.is_none());
100 }
101
102 #[tokio::test]
103 async fn parse_to_xml_object_xml_with_declaration_and_xmlns() {
104 let dir = tempfile::tempdir().unwrap();
105 let path = dir.path().join("meta.xml");
106 let xml = r#"<?xml version="1.0" encoding="UTF-8"?><root xmlns="http://example.com"><a>1</a></root>"#;
107 std::fs::write(&path, xml).unwrap();
108 let out = parse_to_xml_object(path.to_str().unwrap()).await;
109 assert!(out.is_some());
110 let obj = out.unwrap();
111 assert!(obj.get("?xml").is_some());
112 let root = obj.get("root").and_then(|r| r.as_object()).unwrap();
113 assert_eq!(
114 root.get("@xmlns").and_then(|v| v.as_str()),
115 Some("http://example.com")
116 );
117 }
118}