1extern crate xml;
2
3pub mod error;
4pub mod attribute;
5
6use std::io::prelude::*;
7
8use std::convert::AsRef;
9
10use std::iter::Iterator;
11
12use std::slice;
13
14use std::fmt;
15
16use xml::reader::{XmlEvent as ReaderEvent, EventReader};
17use xml::writer::{XmlEvent as WriterEvent, EventWriter};
18use xml::name::Name;
19use xml::namespace::NS_NO_PREFIX;
20
21use error::Error;
22
23use attribute::Attribute;
24
25#[derive(Clone, PartialEq, Eq)]
26pub struct Element {
27 name: String,
28 namespace: Option<String>,
29 attributes: Vec<Attribute>,
30 children: Vec<Fork>,
31}
32
33impl fmt::Debug for Element {
34 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
35 if let Some(ref ns) = self.namespace {
36 write!(fmt, "<{{{}}}{}", ns, self.name)?;
37 }
38 else {
39 write!(fmt, "<{}", self.name)?;
40 }
41 for attr in &self.attributes {
42 write!(fmt, " {}", attr)?;
43 }
44 write!(fmt, ">")?;
45 for child in &self.children {
46 match *child {
47 Fork::Element(ref e) => {
48 write!(fmt, "{:?}", e)?;
49 },
50 Fork::Text(ref s) => {
51 write!(fmt, "{}", s)?;
52 },
53 }
54 }
55 write!(fmt, "</{}>", self.name)?;
56 Ok(())
57 }
58}
59
60#[derive(Clone, Debug, PartialEq, Eq)]
61pub enum Fork {
62 Element(Element),
63 Text(String),
64}
65
66impl Element {
67 pub fn new(name: String, namespace: Option<String>, attributes: Vec<Attribute>) -> Element {
68 Element {
69 name: name,
70 namespace: namespace,
71 attributes: attributes,
72 children: Vec::new(),
73 }
74 }
75
76 pub fn builder<S: Into<String>>(name: S) -> ElementBuilder {
77 ElementBuilder {
78 name: name.into(),
79 text: None,
80 namespace: None,
81 attributes: Vec::new(),
82 }
83 }
84
85 pub fn name(&self) -> &str {
86 &self.name
87 }
88
89 pub fn ns(&self) -> Option<&str> {
90 self.namespace.as_ref()
91 .map(String::as_ref)
92 }
93
94 pub fn attr(&self, name: &str) -> Option<&str> {
95 for attr in &self.attributes {
96 if attr.name == name {
97 return Some(&attr.value);
98 }
99 }
100 None
101 }
102
103 pub fn is<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
104 let ns = self.namespace.as_ref().map(String::as_ref);
105 self.name == name.as_ref() && ns == Some(namespace.as_ref())
106 }
107
108 pub fn from_reader<R: Read>(reader: &mut EventReader<R>) -> Result<Element, Error> {
109 loop {
110 let e = reader.next()?;
111 match e {
112 ReaderEvent::StartElement { name, attributes, namespace } => {
113 let attributes = attributes.into_iter()
114 .map(|o| Attribute::new(o.name.local_name, o.value))
115 .collect();
116 let ns = if let Some(ref prefix) = name.prefix {
117 namespace.get(prefix)
118 }
119 else {
120 namespace.get(NS_NO_PREFIX)
121 }.map(|s| s.to_owned());
122 let mut root = Element::new(name.local_name, ns, attributes);
123 root.from_reader_inner(reader)?;
124 return Ok(root);
125 },
126 ReaderEvent::EndDocument => {
127 return Err(Error::EndOfDocument);
128 },
129 _ => () // TODO: may need more errors
130 }
131 }
132 }
133
134 fn from_reader_inner<R: Read>(&mut self, reader: &mut EventReader<R>) -> Result<(), Error> {
135 loop {
136 let e = reader.next()?;
137 match e {
138 ReaderEvent::StartElement { name, attributes, namespace } => {
139 let attributes = attributes.into_iter()
140 .map(|o| Attribute::new(o.name.local_name, o.value))
141 .collect();
142 let ns = if let Some(ref prefix) = name.prefix {
143 namespace.get(prefix)
144 }
145 else {
146 namespace.get(NS_NO_PREFIX)
147 }.map(|s| s.to_owned());
148 let elem = Element::new(name.local_name, ns, attributes);
149 let elem_ref = self.append_child(elem);
150 elem_ref.from_reader_inner(reader)?;
151 },
152 ReaderEvent::EndElement { .. } => {
153 // TODO: may want to check whether we're closing the correct element
154 return Ok(());
155 },
156 ReaderEvent::Characters(s) => {
157 self.append_text_node(s);
158 },
159 ReaderEvent::CData(s) => {
160 self.append_text_node(s);
161 },
162 ReaderEvent::EndDocument => {
163 return Err(Error::EndOfDocument);
164 },
165 _ => (), // TODO: may need to implement more
166 }
167 }
168 }
169
170 pub fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), Error> {
171 let name = if let Some(ref ns) = self.namespace {
172 Name::qualified(&self.name, &ns, None)
173 }
174 else {
175 Name::local(&self.name)
176 };
177 let mut start = WriterEvent::start_element(name);
178 if let Some(ref ns) = self.namespace {
179 start = start.default_ns(ns.as_ref());
180 }
181 for attr in &self.attributes { // TODO: I think this could be done a lot more efficiently
182 start = start.attr(Name::local(&attr.name), &attr.value);
183 }
184 writer.write(start)?;
185 for child in &self.children {
186 match *child {
187 Fork::Element(ref e) => {
188 e.write_to(writer)?;
189 },
190 Fork::Text(ref s) => {
191 writer.write(WriterEvent::characters(s))?;
192 },
193 }
194 }
195 writer.write(WriterEvent::end_element())?;
196 Ok(())
197 }
198
199 pub fn children<'a>(&'a self) -> Children<'a> {
200 Children {
201 iter: self.children.iter(),
202 }
203 }
204
205 pub fn children_mut<'a>(&'a mut self) -> ChildrenMut<'a> {
206 ChildrenMut {
207 iter: self.children.iter_mut(),
208 }
209 }
210
211 pub fn append_child(&mut self, mut child: Element) -> &mut Element {
212 if child.namespace.is_none() {
213 child.namespace = self.namespace.clone();
214 }
215 self.children.push(Fork::Element(child));
216 if let Fork::Element(ref mut cld) = *self.children.last_mut().unwrap() {
217 cld
218 }
219 else {
220 unreachable!()
221 }
222 }
223
224 pub fn append_text_node<S: Into<String>>(&mut self, child: S) {
225 self.children.push(Fork::Text(child.into()));
226 }
227
228 pub fn text(&self) -> String {
229 let mut ret = String::new();
230 for fork in &self.children {
231 if let Fork::Text(ref s) = *fork {
232 ret += s;
233 }
234 }
235 ret
236 }
237
238 pub fn get_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> Option<&Element> {
239 for fork in &self.children {
240 if let Fork::Element(ref e) = *fork {
241 if e.is(name.as_ref(), namespace.as_ref()) {
242 return Some(e);
243 }
244 }
245 }
246 None
247 }
248
249 pub fn get_child_mut<N: AsRef<str>, NS: AsRef<str>>(&mut self, name: N, namespace: NS) -> Option<&mut Element> {
250 for fork in &mut self.children {
251 if let Fork::Element(ref mut e) = *fork {
252 if e.is(name.as_ref(), namespace.as_ref()) {
253 return Some(e);
254 }
255 }
256 }
257 None
258 }
259
260 pub fn has_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
261 self.get_child(name, namespace).is_some()
262 }
263}
264
265pub struct Children<'a> {
266 iter: slice::Iter<'a, Fork>,
267}
268
269impl<'a> Iterator for Children<'a> {
270 type Item = &'a Element;
271
272 fn next(&mut self) -> Option<&'a Element> {
273 while let Some(item) = self.iter.next() {
274 if let Fork::Element(ref child) = *item {
275 return Some(child);
276 }
277 }
278 None
279 }
280}
281
282pub struct ChildrenMut<'a> {
283 iter: slice::IterMut<'a, Fork>,
284}
285
286impl<'a> Iterator for ChildrenMut<'a> {
287 type Item = &'a mut Element;
288
289 fn next(&mut self) -> Option<&'a mut Element> {
290 while let Some(item) = self.iter.next() {
291 if let Fork::Element(ref mut child) = *item {
292 return Some(child);
293 }
294 }
295 None
296 }
297}
298
299pub struct ElementBuilder {
300 name: String,
301 text: Option<String>,
302 namespace: Option<String>,
303 attributes: Vec<Attribute>,
304}
305
306impl ElementBuilder {
307 pub fn ns<S: Into<String>>(mut self, namespace: S) -> ElementBuilder {
308 self.namespace = Some(namespace.into());
309 self
310 }
311
312 pub fn attr<S: Into<String>, V: Into<String>>(mut self, name: S, value: V) -> ElementBuilder {
313 self.attributes.push(Attribute::new(name, value));
314 self
315 }
316
317 pub fn text<S: Into<String>>(mut self, text: S) -> ElementBuilder {
318 self.text = Some(text.into());
319 self
320 }
321
322 pub fn build(self) -> Element {
323 let mut elem = Element::new(self.name, self.namespace, self.attributes);
324 if let Some(text) = self.text {
325 elem.append_text_node(text);
326 }
327 elem
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use super::*;
334
335 use xml::reader::EventReader;
336 use xml::writer::EventWriter;
337
338 const TEST_STRING: &'static str = r#"<?xml version="1.0" encoding="utf-8"?><root xmlns="root_ns" a="b">meow<child c="d" /><child xmlns="child_ns" d="e" />nya</root>"#;
339
340 fn build_test_tree() -> Element {
341 let mut root = Element::builder("root")
342 .ns("root_ns")
343 .attr("a", "b")
344 .build();
345 root.append_text_node("meow");
346 let child = Element::builder("child")
347 .attr("c", "d")
348 .build();
349 root.append_child(child);
350 let other_child = Element::builder("child")
351 .ns("child_ns")
352 .attr("d", "e")
353 .build();
354 root.append_child(other_child);
355 root.append_text_node("nya");
356 root
357 }
358
359 #[test]
360 fn reader_works() {
361 use std::io::Cursor;
362 let mut reader = EventReader::new(Cursor::new(TEST_STRING));
363 assert_eq!(Element::from_reader(&mut reader).unwrap(), build_test_tree());
364 }
365
366 #[test]
367 fn writer_works() {
368 let root = build_test_tree();
369 let mut out = Vec::new();
370 {
371 let mut writer = EventWriter::new(&mut out);
372 root.write_to(&mut writer).unwrap();
373 }
374 assert_eq!(String::from_utf8(out).unwrap(), TEST_STRING);
375 }
376
377 #[test]
378 fn builder_works() {
379 let elem = Element::builder("a")
380 .ns("b")
381 .attr("c", "d")
382 .text("e")
383 .build();
384 assert_eq!(elem.name(), "a");
385 assert_eq!(elem.ns(), Some("b"));
386 assert_eq!(elem.attr("c"), Some("d"));
387 assert_eq!(elem.attr("x"), None);
388 assert_eq!(elem.text(), "e");
389 assert!(elem.is("a", "b"));
390 }
391
392 #[test]
393 fn children_iter_works() {
394 let root = build_test_tree();
395 let mut iter = root.children();
396 assert!(iter.next().unwrap().is("child", "root_ns"));
397 assert!(iter.next().unwrap().is("child", "child_ns"));
398 assert_eq!(iter.next(), None);
399 }
400
401 #[test]
402 fn get_child_works() {
403 let root = build_test_tree();
404 assert_eq!(root.get_child("child", "inexistent_ns"), None);
405 assert_eq!(root.get_child("not_a_child", "root_ns"), None);
406 assert!(root.get_child("child", "root_ns").unwrap().is("child", "root_ns"));
407 assert!(root.get_child("child", "child_ns").unwrap().is("child", "child_ns"));
408 assert_eq!(root.get_child("child", "root_ns").unwrap().attr("c"), Some("d"));
409 assert_eq!(root.get_child("child", "child_ns").unwrap().attr("d"), Some("e"));
410 }
411}