xml_disassembler/builders/
build_xml_string.rs1use quick_xml::events::{BytesCData, BytesDecl, BytesEnd, BytesStart, BytesText, Event};
4use quick_xml::Writer;
5use serde_json::{Map, Value};
6
7use crate::types::XmlElement;
8
9fn value_to_string(v: &Value) -> String {
10 match v {
11 Value::String(s) => s.clone(),
12 Value::Number(n) => n.to_string(),
13 Value::Bool(b) => b.to_string(),
14 Value::Null => String::new(),
15 _ => serde_json::to_string(v).unwrap_or_default(),
16 }
17}
18
19fn write_element<W: std::io::Write>(
20 writer: &mut Writer<W>,
21 name: &str,
22 content: &Value,
23 indent_level: usize,
24) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
25 let indent = " ".repeat(indent_level);
26 let child_indent = " ".repeat(indent_level + 1);
27
28 match content {
29 Value::Object(obj) => {
30 let (attrs, children): (Vec<_>, Vec<_>) =
31 obj.iter().partition(|(k, _)| k.starts_with('@'));
32
33 let attr_name = |k: &str| k.trim_start_matches('@').to_string();
34
35 let mut text_content = String::new();
36 let mut cdata_content = String::new();
37 let child_elements: Vec<(&String, &Value)> = children
38 .iter()
39 .filter_map(|(k, v)| {
40 if *k == "#text" {
41 text_content = value_to_string(v);
42 None
43 } else if *k == "#cdata" {
44 cdata_content = value_to_string(v);
45 None
46 } else {
47 Some((*k, *v))
48 }
49 })
50 .collect();
51
52 let has_children = child_elements.iter().any(|(_, v)| {
53 v.is_object()
54 || (v.is_array() && v.as_array().map(|a| !a.is_empty()).unwrap_or(false))
55 });
56
57 let attrs: Vec<(String, String)> = attrs
58 .iter()
59 .map(|(k, v)| (attr_name(k), value_to_string(v)))
60 .collect();
61
62 let mut start = BytesStart::new(name);
63 for (k, v) in &attrs {
64 start.push_attribute((k.as_str(), v.as_str()));
65 }
66 writer.write_event(Event::Start(start))?;
67
68 if has_children || !child_elements.is_empty() {
69 writer.write_event(Event::Text(BytesText::new(
70 format!("\n{}", child_indent).as_str(),
71 )))?;
72
73 let child_count = child_elements.len();
74 for (idx, (child_name, child_value)) in child_elements.iter().enumerate() {
75 let is_last = idx == child_count - 1;
76 match child_value {
77 Value::Array(arr) => {
78 let arr_len = arr.len();
79 for (i, item) in arr.iter().enumerate() {
80 let arr_last = i == arr_len - 1;
81 write_element(writer, child_name, item, indent_level + 1)?;
82 if !arr_last {
83 writer.write_event(Event::Text(BytesText::new(
84 format!("\n{}", child_indent).as_str(),
85 )))?;
86 }
87 }
88 if !is_last {
89 writer.write_event(Event::Text(BytesText::new(
90 format!("\n{}", child_indent).as_str(),
91 )))?;
92 }
93 }
94 Value::Object(_) => {
95 write_element(writer, child_name, child_value, indent_level + 1)?;
96 if !is_last {
97 writer.write_event(Event::Text(BytesText::new(
98 format!("\n{}", child_indent).as_str(),
99 )))?;
100 }
101 }
102 _ => {
103 writer
104 .write_event(Event::Start(BytesStart::new(child_name.as_str())))?;
105 writer.write_event(Event::Text(BytesText::new(
107 value_to_string(child_value).as_str(),
108 )))?;
109 writer.write_event(Event::End(BytesEnd::new(child_name.as_str())))?;
110 if !is_last {
111 writer.write_event(Event::Text(BytesText::new(
112 format!("\n{}", child_indent).as_str(),
113 )))?;
114 }
115 }
116 }
117 }
118
119 writer.write_event(Event::Text(BytesText::new(
120 format!("\n{}", indent).as_str(),
121 )))?;
122 } else if !cdata_content.is_empty() || !text_content.is_empty() {
123 if !text_content.is_empty() {
125 writer.write_event(Event::Text(BytesText::new(text_content.as_str())))?;
126 }
127 if !cdata_content.is_empty() {
128 writer.write_event(Event::CData(BytesCData::new(cdata_content.as_str())))?;
129 }
130 }
131
132 writer.write_event(Event::End(BytesEnd::new(name)))?;
133 }
134 Value::Array(arr) => {
135 for item in arr {
136 write_element(writer, name, item, indent_level)?;
137 }
138 }
139 _ => {
140 writer.write_event(Event::Start(BytesStart::new(name)))?;
141 writer.write_event(Event::Text(BytesText::new(
143 value_to_string(content).as_str(),
144 )))?;
145 writer.write_event(Event::End(BytesEnd::new(name)))?;
146 }
147 }
148
149 Ok(())
150}
151
152fn build_xml_from_object(
153 element: &Map<String, Value>,
154) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
155 let mut writer = Writer::new_with_indent(Vec::new(), b' ', 4);
156
157 let (declaration, root_key, root_value) = if let Some(decl) = element.get("?xml") {
158 let root_key = element
159 .keys()
160 .find(|k| *k != "?xml")
161 .cloned()
162 .unwrap_or_else(|| "root".to_string());
163 let root_value = element
164 .get(&root_key)
165 .cloned()
166 .unwrap_or_else(|| Value::Object(Map::new()));
167 (Some(decl), root_key, root_value)
168 } else {
169 let root_key = element
170 .keys()
171 .next()
172 .cloned()
173 .unwrap_or_else(|| "root".to_string());
174 let root_value = element
175 .get(&root_key)
176 .cloned()
177 .unwrap_or_else(|| Value::Object(Map::new()));
178 (None, root_key, root_value)
179 };
180
181 if declaration.is_some() {
182 if let Some(decl) = declaration {
183 if let Some(obj) = decl.as_object() {
184 let version = obj
185 .get("@version")
186 .and_then(|v| v.as_str())
187 .unwrap_or("1.0");
188 let encoding = obj.get("@encoding").and_then(|v| v.as_str());
189 let standalone = obj.get("@standalone").and_then(|v| v.as_str());
190 writer.write_event(Event::Decl(BytesDecl::new(version, encoding, standalone)))?;
191 }
192 }
193 }
194
195 write_element(&mut writer, &root_key, &root_value, 0)?;
196
197 let result = String::from_utf8(writer.into_inner())?;
198 Ok(result.trim_end().to_string())
199}
200
201pub fn build_xml_string(element: &XmlElement) -> String {
203 match element {
204 Value::Object(obj) => build_xml_from_object(obj).unwrap_or_default(),
205 _ => String::new(),
206 }
207}