1use XmlParser;
2use XmlAttribute;
3
4use xml::reader::{XmlEvent};
5use xml::namespace::{Namespace};
6use xml::name::{OwnedName};
7use xml::attribute::{OwnedAttribute};
8
9use std::string::{ToString};
10
11#[derive(Debug, Clone)]
12pub struct XmlElement
13{
14 _event : XmlEvent,
15 _children : Vec<XmlElement>,
16 _data: Option<XmlEvent>,
17}
18
19impl XmlElement
20{
21 pub fn new(event : XmlEvent) -> XmlElement
22 {
23 Self::new_with_children(event, Vec::new())
24 }
25
26 pub fn new_with_children(event : XmlEvent, children: Vec<XmlElement>) -> XmlElement
27 {
28 Self::custom(event, children, None)
29 }
30
31 pub fn custom(event : XmlEvent, children: Vec<XmlElement>, data: Option<XmlEvent>) -> XmlElement
32 {
33 XmlElement{_event: event, _children:children, _data: data}
34 }
35
36 pub fn parse(data: &str) -> Option<XmlElement>
37 {
38 XmlParser::parse(data).ok()
39 }
40
41 pub fn name(&self) -> &str
42 {
43 match self._event
44 {
45 XmlEvent::StartElement{ref name, ..} => &name.local_name,
46 _ => panic!("somethings gone wrong")
47 }
48 }
49
50 pub fn mut_change_name_to(&mut self, new_name: &str) -> ()
51 {
52 match self._event
53 {
54 XmlEvent::StartElement{ref mut name, ..} => name.local_name = new_name.to_owned(),
55 _ => panic!("somethings gone wrong")
56 }
57 }
58
59 pub fn change_name_to(&self, new_name: &str) -> XmlElement
60 {
61 let name = self.inner_name().clone();
62 let owned_name = OwnedName{local_name: new_name.to_owned(),
63 namespace: name.namespace,
64 prefix: name.prefix};
65 let start_element = XmlEvent::StartElement{name:owned_name,
66 attributes: self.inner_attributes().to_vec(),
67 namespace: self.inner_namespace().clone()};
68 Self::new_with_children(start_element, self.children().clone().to_vec())
69 }
70
71 pub fn mut_change_data(&mut self, new_data: &str) -> ()
72 {
73 self._data = Some(XmlEvent::Characters(new_data.to_owned()))
74 }
75
76 pub fn data(&self) -> Option<&str>
77 {
78 match self._data
79 {
80 None => None,
81 Some(ref e) => Some(Self::extract_data(e))
82 }
83 }
84
85 fn extract_data(event : &XmlEvent) -> &str
86 {
87 match event
88 {
89 &XmlEvent::Characters(ref c) => c,
90 _ => panic!("somethings gone wrong")
91 }
92 }
93
94 pub fn has_attributes(&self) -> bool
95 {
96 !self.attributes().is_empty()
97 }
98
99 pub fn attributes(&self) -> Vec<XmlAttribute>
100 {
101 self.inner_attributes().iter().map(|a| XmlAttribute::new(&a)).collect()
102 }
103
104 pub fn attribute_with_name(&self, name : &str) -> Option<XmlAttribute>
105 {
106 self.attributes()
107 .into_iter()
108 .filter(|a| a.name() == name)
109 .next()
110 }
111
112 pub fn attribute_value_of(&self, name: &str) -> Option<&str>
113 {
114 self.attribute_with_name(name).map(|a| a.value())
115 }
116
117 pub fn children_with_name(&self, name : &str) -> Vec<&XmlElement>
118 {
119 self._children.iter().filter(|c| c.name() == name).collect()
120 }
121
122 pub fn descendents_with_name(&self, name : &str) -> Vec<&XmlElement>
123 {
124 self._children.iter()
125 .flat_map(|c| Self::descendents_from_child(c, name))
126 .collect()
127 }
128
129 fn descendents_from_child<'a>(child: &'a XmlElement, name: &str) -> Vec<&'a XmlElement>
130 {
131 let mut elements = child.descendents_with_name(name);
132 if child.name() == name
133 {elements.push(child)}
134 elements
135 }
136
137 pub fn children(&self) -> &Vec<XmlElement>
138 {
139 &self._children
140 }
141
142 pub fn mut_children(&mut self) -> &mut Vec<XmlElement>
143 {
144 &mut self._children
145 }
146
147 pub fn has_children(&self) -> bool
148 {
149 !self.children().is_empty()
150 }
151
152 fn inner_attributes(&self) -> &Vec<OwnedAttribute>
153 {
154 match self._event
155 {
156 XmlEvent::StartElement{ref attributes, ..} => attributes,
157 _ => panic!("somethings gone wrong")
158 }
159 }
160
161 fn inner_namespace(&self) -> &Namespace
162 {
163 match self._event
164 {
165 XmlEvent::StartElement{ref namespace, ..} => namespace,
166 _ => panic!("somethings gone wrong")
167 }
168 }
169
170 fn inner_name(&self) -> &OwnedName
171 {
172 match self._event
173 {
174 XmlEvent::StartElement{ref name, ..} => name,
175 _ => panic!("somethings gone wrong")
176 }
177 }
178}
179
180impl ToString for XmlElement
181{
182 fn to_string(&self) -> String
183 {
184 let mut start_element = format!("<{}", self.name());
185 if self.has_attributes()
186 {
187 let attributes = self.attributes().iter().map(|a| a.to_string()).collect::<Vec<String>>().join(" ");
188 start_element = format!("{} {}", start_element, attributes);
189 }
190
191 if !self.has_children()
192 {
193 return format!("{}/>", start_element);
194 }
195
196 start_element.push('>');
197 let end = format!("</{}>", self.name());
198 let children = self.children().iter().map(|c| "\t".to_owned() + &c.to_string()).collect::<Vec<String>>().join("\n");
199 [start_element, children, end].join("\n")
200
201 }
202}
203
204
205#[cfg(test)]
206mod xml_element_tests
207{
208 use super::{XmlElement, XmlAttribute};
209
210 use xml::reader::{XmlEvent};
211 use xml::namespace::{Namespace};
212 use xml::name::{OwnedName};
213 use xml::attribute::{OwnedAttribute};
214
215 #[test]
216 fn can_create_an_element() -> ()
217 {
218 let name = OwnedName{local_name: "a name".to_owned(), namespace: None, prefix: None};
219 let start_element = XmlEvent::StartElement{name:name, attributes:Vec::new(), namespace: Namespace::empty()};
220 let element = XmlElement::new(start_element);
221 assert_eq!(element.name(), "a name");
222 }
223
224 #[test]
225 fn can_get_attributes_by_name() -> ()
226 {
227 let att = OwnedAttribute{name:owned_name_from("name"), value: "a value".to_owned()};
228 let start_element = XmlEvent::StartElement{name:owned_name_from("name"), attributes:vec![att], namespace: Namespace::empty()};
229 let element = XmlElement::new(start_element);
230 assert_eq!(element.attribute_with_name("name").map(|a| a.value().to_owned()).unwrap(), "a value");
231 }
232
233 #[test]
234 fn can_get_attributes_value_from_key() -> ()
235 {
236 let att = OwnedAttribute{name:owned_name_from("name"), value: "a value".to_owned()};
237 let start_element = XmlEvent::StartElement{name:owned_name_from("name"), attributes:vec![att], namespace: Namespace::empty()};
238 let element = XmlElement::new(start_element);
239 assert_eq!(element.attribute_value_of("name").unwrap(), "a value");
240 }
241
242 #[test]
243 fn attributes_have_names() -> ()
244 {
245 let att = OwnedAttribute{name:owned_name_from("name"), value: "a value".to_owned()};
246 let element = XmlAttribute::new(&att);
247 assert_eq!(element.name(), "name");
248 }
249
250 #[test]
251 fn attributes_have_values() -> ()
252 {
253 let att = OwnedAttribute{name:owned_name_from("name"), value: "a value".to_owned()};
254 let element = XmlAttribute::new(&att);
255 assert_eq!(element.value(), "a value");
256 }
257
258 #[test]
259 fn parse_can_fail() -> ()
260 {
261 let element = XmlElement::parse("<bad_element>");
262 assert_eq!(element.is_none(), true);
263 }
264
265 #[test]
266 fn to_string_no_children_test()
267 {
268 let data = "<data name=\"x\"></data>";
269 let element = XmlElement::parse(data);
270 assert_eq!(element.unwrap().to_string(), "<data name=\"x\"/>")
271 }
272
273 #[test]
274 fn to_string_children_test()
275 {
276 let data = "<data name=\"x\">\n\t<something/>\n</data>";
277 let element = XmlElement::parse(data);
278 assert_eq!(element.unwrap().to_string(), data)
279 }
280
281 #[test]
282 fn to_string_children_with_attributes_test()
283 {
284 let data = "<data name=\"x\">\n\t<something name=\"x\"/>\n</data>";
285 let element = XmlElement::parse(data);
286 assert_eq!(element.unwrap().to_string(), data)
287 }
288
289 #[test]
290 fn change_name_test()
291 {
292 let data = "<data name=\"x\">\n\t<something name=\"x\"/>\n</data>";
293 assert_eq!(XmlElement::parse(data).unwrap().change_name_to("y").name(), "y")
294 }
295
296 #[test]
297 fn mutating_name_change_test()
298 {
299 let data = "<data name=\"x\">\n\t<something name=\"x\"/>\n</data>";
300 let mut element = XmlElement::parse(data).unwrap();
301 assert_eq!(element.name(), "data");
302 element.mut_change_name_to("y");
303 assert_eq!(element.name(), "y");
304 }
305
306
307 fn owned_name_from(name: &str) -> OwnedName
308 {
309 OwnedName{local_name: name.to_owned(), namespace: None, prefix: None}
310 }
311
312}