1use parking_lot::Mutex;
5use std::sync::Arc;
6
7#[derive(Debug)]
9struct NodeData {
10 name: String,
11 value: String,
12 children: Vec<XmlNode>,
13 parent: Option<XmlNodeWeak>,
14}
15
16type XmlNodeInner = Arc<Mutex<NodeData>>;
17type XmlNodeWeak = std::sync::Weak<Mutex<NodeData>>;
18
19#[derive(Debug, Clone)]
21pub struct XmlNode {
22 inner: XmlNodeInner,
23}
24
25static EMPTY_NODE: once_cell::sync::Lazy<XmlNode> = once_cell::sync::Lazy::new(|| XmlNode {
27 inner: Arc::new(Mutex::new(NodeData {
28 name: String::new(),
29 value: String::new(),
30 children: Vec::new(),
31 parent: None,
32 })),
33});
34
35impl XmlNode {
36 pub fn new(name: &str) -> Self {
38 XmlNode {
39 inner: Arc::new(Mutex::new(NodeData {
40 name: name.to_string(),
41 value: String::new(),
42 children: Vec::new(),
43 parent: None,
44 })),
45 }
46 }
47
48 pub fn empty() -> Self {
50 EMPTY_NODE.clone()
51 }
52
53 pub fn is_empty(&self) -> bool {
55 self.inner.lock().name.is_empty()
56 }
57
58 pub fn name(&self) -> String {
60 self.inner.lock().name.clone()
61 }
62
63 pub fn value(&self) -> String {
65 self.inner.lock().value.clone()
66 }
67
68 pub fn set_name(&self, name: &str) {
70 self.inner.lock().name = name.to_string();
71 }
72
73 pub fn set_value(&self, value: &str) {
75 self.inner.lock().value = value.to_string();
76 }
77
78 pub fn append_child(&self, name: &str) -> XmlNode {
80 let child = XmlNode::new(name);
81 {
82 child.inner.lock().parent = Some(Arc::downgrade(&self.inner));
83 }
84 self.inner.lock().children.push(child.clone());
85 child
86 }
87
88 pub fn prepend_child(&self, name: &str) -> XmlNode {
90 let child = XmlNode::new(name);
91 {
92 child.inner.lock().parent = Some(Arc::downgrade(&self.inner));
93 }
94 self.inner.lock().children.insert(0, child.clone());
95 child
96 }
97
98 pub fn append_child_value(&self, name: &str, value: &str) -> XmlNode {
100 let child = self.append_child(name);
101 child.set_value(value);
102 child
103 }
104
105 pub fn prepend_child_value(&self, name: &str, value: &str) -> XmlNode {
107 let child = self.prepend_child(name);
108 child.set_value(value);
109 child
110 }
111
112 pub fn set_child_value(&self, name: &str, value: &str) -> bool {
114 let data = self.inner.lock();
115 for child in &data.children {
116 if child.name() == name {
117 child.set_value(value);
118 return true;
119 }
120 }
121 drop(data);
123 self.append_child_value(name, value);
124 true
125 }
126
127 pub fn child(&self, name: &str) -> XmlNode {
129 let data = self.inner.lock();
130 for child in &data.children {
131 if child.name() == name {
132 return child.clone();
133 }
134 }
135 XmlNode::empty()
136 }
137
138 pub fn child_value(&self, name: &str) -> String {
140 let ch = self.child(name);
141 if ch.is_empty() {
142 String::new()
143 } else {
144 ch.value()
145 }
146 }
147
148 pub fn child_value_self(&self) -> String {
150 self.value()
151 }
152
153 pub fn first_child(&self) -> XmlNode {
155 let data = self.inner.lock();
156 data.children
157 .first()
158 .cloned()
159 .unwrap_or_else(XmlNode::empty)
160 }
161
162 pub fn last_child(&self) -> XmlNode {
164 let data = self.inner.lock();
165 data.children.last().cloned().unwrap_or_else(XmlNode::empty)
166 }
167
168 pub fn next_sibling(&self) -> XmlNode {
170 self.sibling_offset(1, None)
171 }
172
173 pub fn next_sibling_named(&self, name: &str) -> XmlNode {
175 self.sibling_offset(1, Some(name))
176 }
177
178 pub fn previous_sibling(&self) -> XmlNode {
180 self.sibling_offset(-1, None)
181 }
182
183 pub fn previous_sibling_named(&self, name: &str) -> XmlNode {
185 self.sibling_offset(-1, Some(name))
186 }
187
188 fn sibling_offset(&self, direction: i32, name_filter: Option<&str>) -> XmlNode {
189 let parent_weak = {
190 let data = self.inner.lock();
191 match &data.parent {
192 Some(w) => w.clone(),
193 None => return XmlNode::empty(),
194 }
195 };
196 let parent = match parent_weak.upgrade() {
197 Some(p) => p,
198 None => return XmlNode::empty(),
199 };
200 let parent_data = parent.lock();
201 let self_ptr = Arc::as_ptr(&self.inner);
202 let mut found_self = false;
203 let iter: Box<dyn Iterator<Item = &XmlNode>> = if direction > 0 {
204 Box::new(parent_data.children.iter())
205 } else {
206 Box::new(parent_data.children.iter().rev())
207 };
208 for child in iter {
209 if found_self {
210 if let Some(name) = name_filter {
211 if child.name() == name {
212 return child.clone();
213 }
214 } else {
215 return child.clone();
216 }
217 }
218 if Arc::as_ptr(&child.inner) == self_ptr {
219 found_self = true;
220 }
221 }
222 XmlNode::empty()
223 }
224
225 pub fn parent(&self) -> XmlNode {
227 let data = self.inner.lock();
228 match &data.parent {
229 Some(w) => match w.upgrade() {
230 Some(p) => XmlNode { inner: p },
231 None => XmlNode::empty(),
232 },
233 None => XmlNode::empty(),
234 }
235 }
236
237 pub fn remove_child_named(&self, name: &str) {
239 let mut data = self.inner.lock();
240 data.children.retain(|c| c.name() != name);
241 }
242
243 pub fn remove_child(&self, child: &XmlNode) {
245 let child_ptr = Arc::as_ptr(&child.inner);
246 let mut data = self.inner.lock();
247 data.children.retain(|c| Arc::as_ptr(&c.inner) != child_ptr);
248 }
249
250 pub fn deep_clone(&self) -> XmlNode {
252 let data = self.inner.lock();
253 let new_node = XmlNode::new(&data.name);
254 new_node.set_value(&data.value);
255 for child in &data.children {
256 let child_clone = child.deep_clone();
257 child_clone.inner.lock().parent = Some(Arc::downgrade(&new_node.inner));
258 new_node.inner.lock().children.push(child_clone);
259 }
260 new_node
261 }
262
263 pub fn append_copy(&self, other: &XmlNode) -> XmlNode {
265 let copy = other.deep_clone();
266 copy.inner.lock().parent = Some(Arc::downgrade(&self.inner));
267 self.inner.lock().children.push(copy.clone());
268 copy
269 }
270
271 pub fn prepend_copy(&self, other: &XmlNode) -> XmlNode {
273 let copy = other.deep_clone();
274 copy.inner.lock().parent = Some(Arc::downgrade(&self.inner));
275 self.inner.lock().children.insert(0, copy.clone());
276 copy
277 }
278
279 pub fn to_xml(&self) -> String {
281 let mut out = String::new();
282 self.write_xml(&mut out, 0);
283 out
284 }
285
286 fn write_xml(&self, out: &mut String, _depth: usize) {
287 let data = self.inner.lock();
288 if data.name.is_empty() {
289 return;
290 }
291 out.push('<');
292 out.push_str(&data.name);
293 out.push('>');
294 if !data.value.is_empty() {
295 xml_escape_into(out, &data.value);
296 }
297 for child in &data.children {
298 child.write_xml(out, _depth + 1);
299 }
300 out.push_str("</");
301 out.push_str(&data.name);
302 out.push('>');
303 }
304
305 pub fn same_as(&self, other: &XmlNode) -> bool {
307 Arc::ptr_eq(&self.inner, &other.inner)
308 }
309}
310
311fn xml_escape_into(out: &mut String, s: &str) {
312 for c in s.chars() {
313 match c {
314 '&' => out.push_str("&"),
315 '<' => out.push_str("<"),
316 '>' => out.push_str(">"),
317 '"' => out.push_str("""),
318 '\'' => out.push_str("'"),
319 _ => out.push(c),
320 }
321 }
322}
323
324pub fn xml_escape(s: &str) -> String {
325 let mut out = String::new();
326 xml_escape_into(&mut out, s);
327 out
328}
329
330pub fn xml_unescape(s: &str) -> String {
331 s.replace("&", "&")
332 .replace("<", "<")
333 .replace(">", ">")
334 .replace(""", "\"")
335 .replace("'", "'")
336}