nv_xml/
xml_element.rs

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}