element.rs

  1//! Provides an `Element` type, which represents DOM nodes, and a builder to create them with.
  2
  3use std::io::prelude::*;
  4use std::io::Cursor;
  5use std::collections::BTreeMap;
  6use std::iter::FromIterator;
  7
  8use std::fmt;
  9
 10use error::Error;
 11
 12use xml::reader::{XmlEvent as ReaderEvent, EventReader};
 13use xml::writer::{XmlEvent as WriterEvent, EventWriter};
 14use xml::name::Name;
 15use xml::namespace::NS_NO_PREFIX;
 16
 17use std::str::FromStr;
 18
 19use std::slice;
 20
 21use convert::{IntoElements, IntoAttributeValue, ElementEmitter};
 22
 23#[derive(Clone, PartialEq, Eq)]
 24/// A struct representing a DOM Element.
 25pub struct Element {
 26    name: String,
 27    namespace: Option<String>,
 28    attributes: BTreeMap<String, String>,
 29    children: Vec<Node>,
 30}
 31
 32
 33impl fmt::Debug for Element {
 34    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 35        write!(fmt, "<{}", self.name)?;
 36        if let Some(ref ns) = self.namespace {
 37            write!(fmt, " xmlns=\"{}\"", ns)?;
 38        }
 39        for attr in &self.attributes {
 40            write!(fmt, " {}=\"{}\"", attr.0, attr.1)?;
 41        }
 42        if self.children.is_empty() {
 43            write!(fmt, "/>")?;
 44        }
 45        else {
 46            write!(fmt, ">")?;
 47            for child in &self.children {
 48                match *child {
 49                    Node::Element(ref e) => {
 50                        write!(fmt, "{:?}", e)?;
 51                    },
 52                    Node::Text(ref s) => {
 53                        write!(fmt, "{}", s)?;
 54                    },
 55                }
 56            }
 57            write!(fmt, "</{}>", self.name)?;
 58        }
 59        Ok(())
 60    }
 61}
 62
 63impl FromStr for Element {
 64    type Err = Error;
 65
 66    fn from_str(s: &str) -> Result<Element, Error> {
 67        let mut reader = EventReader::new(Cursor::new(s));
 68        Element::from_reader(&mut reader)
 69    }
 70}
 71
 72/// A node in an element tree.
 73#[derive(Clone, Debug, PartialEq, Eq)]
 74pub enum Node {
 75    /// An `Element`.
 76    Element(Element),
 77    /// A text node.
 78    Text(String),
 79}
 80
 81impl Element {
 82    fn new(name: String, namespace: Option<String>, attributes: BTreeMap<String, String>, children: Vec<Node>) -> Element {
 83        Element {
 84            name: name,
 85            namespace: namespace,
 86            attributes: attributes,
 87            children: children,
 88        }
 89    }
 90
 91    /// Return a builder for an `Element` with the given `name`.
 92    ///
 93    /// # Examples
 94    ///
 95    /// ```
 96    /// use minidom::Element;
 97    ///
 98    /// let elem = Element::builder("name")
 99    ///                    .ns("namespace")
100    ///                    .attr("name", "value")
101    ///                    .append("inner")
102    ///                    .build();
103    ///
104    /// assert_eq!(elem.name(), "name");
105    /// assert_eq!(elem.ns(), Some("namespace"));
106    /// assert_eq!(elem.attr("name"), Some("value"));
107    /// assert_eq!(elem.attr("inexistent"), None);
108    /// assert_eq!(elem.text(), "inner");
109    /// ```
110    pub fn builder<S: Into<String>>(name: S) -> ElementBuilder {
111        ElementBuilder {
112            root: Element::new(name.into(), None, BTreeMap::new(), Vec::new()),
113        }
114    }
115
116    /// Returns a bare minimum `Element` with this name.
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// use minidom::Element;
122    ///
123    /// let bare = Element::bare("name");
124    ///
125    /// assert_eq!(bare.name(), "name");
126    /// assert_eq!(bare.ns(), None);
127    /// assert_eq!(bare.attr("name"), None);
128    /// assert_eq!(bare.text(), "");
129    /// ```
130    pub fn bare<S: Into<String>>(name: S) -> Element {
131        Element {
132            name: name.into(),
133            namespace: None,
134            attributes: BTreeMap::new(),
135            children: Vec::new(),
136        }
137    }
138
139    /// Returns a reference to the name of this element.
140    pub fn name(&self) -> &str {
141        &self.name
142    }
143
144    /// Returns a reference to the namespace of this element, if it has one, else `None`.
145    pub fn ns(&self) -> Option<&str> {
146        self.namespace.as_ref()
147                      .map(String::as_ref)
148    }
149
150    /// Returns a reference to the value of the given attribute, if it exists, else `None`.
151    pub fn attr(&self, name: &str) -> Option<&str> {
152        if let Some(value) = self.attributes.get(name) {
153            return Some(&value)
154        }
155        None
156    }
157
158    /// Modifies the value of an attribute.
159    pub fn set_attr<S: Into<String>, V: IntoAttributeValue>(&mut self, name: S, val: V) {
160        let name = name.into();
161        let val = val.into_attribute_value();
162
163        if let Some(value) = self.attributes.get_mut(&name) {
164            *value = val.expect("removing existing value via set_attr, this is not yet supported (TODO)"); // TODO
165            return;
166        }
167
168        if let Some(val) = val {
169            self.attributes.insert(name, val);
170        }
171    }
172
173    /// Returns whether the element has the given name and namespace.
174    ///
175    /// # Examples
176    ///
177    /// ```
178    /// use minidom::Element;
179    ///
180    /// let elem = Element::builder("name").ns("namespace").build();
181    ///
182    /// assert_eq!(elem.is("name", "namespace"), true);
183    /// assert_eq!(elem.is("name", "wrong"), false);
184    /// assert_eq!(elem.is("wrong", "namespace"), false);
185    /// assert_eq!(elem.is("wrong", "wrong"), false);
186    /// ```
187    pub fn is<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
188        let ns = self.namespace.as_ref().map(String::as_ref);
189        self.name == name.as_ref() && ns == Some(namespace.as_ref())
190    }
191
192    /// Parse a document from an `EventReader`.
193    pub fn from_reader<R: Read>(reader: &mut EventReader<R>) -> Result<Element, Error> {
194        loop {
195            let e = reader.next()?;
196            match e {
197                ReaderEvent::StartElement { name, attributes, namespace } => {
198                    let attributes = attributes.into_iter()
199                                               .map(|o| {
200                                                    (match o.name.prefix {
201                                                        Some(prefix) => format!("{}:{}", prefix, o.name.local_name),
202                                                        None => o.name.local_name
203                                                    },
204                                                    o.value)
205                                                })
206                                               .collect();
207                    let ns = if let Some(ref prefix) = name.prefix {
208                        namespace.get(prefix)
209                    }
210                    else {
211                        namespace.get(NS_NO_PREFIX)
212                    }.map(|s| s.to_owned());
213
214                    let mut root = Element::new(name.local_name, ns, attributes, Vec::new());
215                    root.from_reader_inner(reader)?;
216                    return Ok(root);
217                },
218                ReaderEvent::EndDocument => {
219                    return Err(Error::EndOfDocument);
220                },
221                _ => () // TODO: may need more errors
222            }
223        }
224    }
225
226    fn from_reader_inner<R: Read>(&mut self, reader: &mut EventReader<R>) -> Result<(), Error> {
227        loop {
228            let e = reader.next()?;
229            match e {
230                ReaderEvent::StartElement { name, attributes, namespace } => {
231                    let attributes = attributes.into_iter()
232                                               .map(|o| {
233                                                    (match o.name.prefix {
234                                                        Some(prefix) => format!("{}:{}", prefix, o.name.local_name),
235                                                        None => o.name.local_name
236                                                    },
237                                                    o.value)
238                                                })
239                                               .collect();
240                    let ns = if let Some(ref prefix) = name.prefix {
241                        namespace.get(prefix)
242                    }
243                    else {
244                        namespace.get(NS_NO_PREFIX)
245                    }.map(|s| s.to_owned());
246                    let elem = Element::new(name.local_name, ns, attributes, Vec::with_capacity(1));
247                    let elem_ref = self.append_child(elem);
248                    elem_ref.from_reader_inner(reader)?;
249                },
250                ReaderEvent::EndElement { .. } => {
251                    // TODO: may want to check whether we're closing the correct element
252                    return Ok(());
253                },
254                ReaderEvent::Characters(s) => {
255                    self.append_text_node(s);
256                },
257                ReaderEvent::CData(s) => {
258                    self.append_text_node(s);
259                },
260                ReaderEvent::EndDocument => {
261                    return Err(Error::EndOfDocument);
262                },
263                _ => (), // TODO: may need to implement more
264            }
265        }
266    }
267
268    /// Output a document to an `EventWriter`.
269    pub fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), Error> {
270        let name = if let Some(ref ns) = self.namespace {
271            Name::qualified(&self.name, &ns, None)
272        }
273        else {
274            Name::local(&self.name)
275        };
276        let mut start = WriterEvent::start_element(name);
277        if let Some(ref ns) = self.namespace {
278            start = start.default_ns(ns.as_ref());
279        }
280        for attr in &self.attributes { // TODO: I think this could be done a lot more efficiently
281            start = start.attr(Name::local(&attr.0), &attr.1);
282        }
283        writer.write(start)?;
284        for child in &self.children {
285            match *child {
286                Node::Element(ref e) => {
287                    e.write_to(writer)?;
288                },
289                Node::Text(ref s) => {
290                    writer.write(WriterEvent::characters(s))?;
291                },
292            }
293        }
294        writer.write(WriterEvent::end_element())?;
295        Ok(())
296    }
297
298    /// Returns an iterator over references to the children of this element.
299    ///
300    /// # Examples
301    ///
302    /// ```
303    /// use minidom::Element;
304    ///
305    /// let elem: Element = "<root><child1 /><child2 /><child3 /></root>".parse().unwrap();
306    ///
307    /// let mut iter = elem.children();
308    /// assert_eq!(iter.next().unwrap().name(), "child1");
309    /// assert_eq!(iter.next().unwrap().name(), "child2");
310    /// assert_eq!(iter.next().unwrap().name(), "child3");
311    /// assert_eq!(iter.next(), None);
312    /// ```
313    pub fn children<'a>(&'a self) -> Children<'a> {
314        Children {
315            iter: self.children.iter(),
316        }
317    }
318
319    /// Returns an iterator over mutable references to the children of this element.
320    pub fn children_mut<'a>(&'a mut self) -> ChildrenMut<'a> {
321        ChildrenMut {
322            iter: self.children.iter_mut(),
323        }
324    }
325
326    fn propagate_namespaces(&mut self) {
327        let ns = self.namespace.clone();
328        for child in self.children_mut() {
329            if child.namespace.is_none() {
330                child.namespace = ns.clone();
331                child.propagate_namespaces();
332            }
333        }
334    }
335
336    /// Appends a child node to the `Element`, returning the appended node.
337    ///
338    /// # Examples
339    ///
340    /// ```
341    /// use minidom::Element;
342    ///
343    /// let mut elem = Element::bare("root");
344    ///
345    /// assert_eq!(elem.children().count(), 0);
346    ///
347    /// elem.append_child(Element::bare("child"));
348    ///
349    /// {
350    ///     let mut iter = elem.children();
351    ///     assert_eq!(iter.next().unwrap().name(), "child");
352    ///     assert_eq!(iter.next(), None);
353    /// }
354    ///
355    /// let child = elem.append_child(Element::bare("new"));
356    ///
357    /// assert_eq!(child.name(), "new");
358    /// ```
359    pub fn append_child(&mut self, mut child: Element) -> &mut Element {
360        if child.namespace.is_none() && self.namespace.is_some() {
361            child.namespace = self.namespace.clone();
362            child.propagate_namespaces();
363        }
364        self.children.push(Node::Element(child));
365        if let Node::Element(ref mut cld) = *self.children.last_mut().unwrap() {
366            cld
367        }
368        else {
369            unreachable!()
370        }
371    }
372
373    /// Appends a text node to an `Element`.
374    ///
375    /// # Examples
376    ///
377    /// ```
378    /// use minidom::Element;
379    ///
380    /// let mut elem = Element::bare("node");
381    ///
382    /// assert_eq!(elem.text(), "");
383    ///
384    /// elem.append_text_node("text");
385    ///
386    /// assert_eq!(elem.text(), "text");
387    /// ```
388    pub fn append_text_node<S: Into<String>>(&mut self, child: S) {
389        self.children.push(Node::Text(child.into()));
390    }
391
392    /// Appends a node to an `Element`.
393    ///
394    /// # Examples
395    ///
396    /// ```
397    /// use minidom::{Element, Node};
398    ///
399    /// let mut elem = Element::bare("node");
400    ///
401    /// elem.append_node(Node::Text("hello".to_owned()));
402    ///
403    /// assert_eq!(elem.text(), "hello");
404    /// ```
405    pub fn append_node(&mut self, node: Node) {
406        self.children.push(node);
407    }
408
409    /// Returns the concatenation of all text nodes in the `Element`.
410    ///
411    /// # Examples
412    ///
413    /// ```
414    /// use minidom::Element;
415    ///
416    /// let elem: Element = "<node>hello, world!</node>".parse().unwrap();
417    ///
418    /// assert_eq!(elem.text(), "hello, world!");
419    /// ```
420    pub fn text(&self) -> String {
421        let mut ret = String::new();
422        for fork in &self.children {
423            if let Node::Text(ref s) = *fork {
424                ret += s;
425            }
426        }
427        ret
428    }
429
430    /// Returns a reference to the first child element with the specific name and namespace, if it
431    /// exists in the direct descendants of this `Element`, else returns `None`.
432    ///
433    /// # Examples
434    ///
435    /// ```
436    /// use minidom::Element;
437    ///
438    /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
439    ///
440    /// assert!(elem.get_child("a", "ns").unwrap().is("a", "ns"));
441    /// assert!(elem.get_child("a", "other_ns").unwrap().is("a", "other_ns"));
442    /// assert!(elem.get_child("b", "ns").unwrap().is("b", "ns"));
443    /// assert_eq!(elem.get_child("c", "ns"), None);
444    /// assert_eq!(elem.get_child("b", "other_ns"), None);
445    /// assert_eq!(elem.get_child("a", "inexistent_ns"), None);
446    /// ```
447    pub fn get_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> Option<&Element> {
448        for fork in &self.children {
449            if let Node::Element(ref e) = *fork {
450                if e.is(name.as_ref(), namespace.as_ref()) {
451                    return Some(e);
452                }
453            }
454        }
455        None
456    }
457
458    /// Returns a mutable reference to the first child element with the specific name and namespace,
459    /// if it exists in the direct descendants of this `Element`, else returns `None`.
460    pub fn get_child_mut<N: AsRef<str>, NS: AsRef<str>>(&mut self, name: N, namespace: NS) -> Option<&mut Element> {
461        for fork in &mut self.children {
462            if let Node::Element(ref mut e) = *fork {
463                if e.is(name.as_ref(), namespace.as_ref()) {
464                    return Some(e);
465                }
466            }
467        }
468        None
469    }
470
471    /// Returns whether a specific child with this name and namespace exists in the direct
472    /// descendants of the `Element`.
473    ///
474    /// # Examples
475    ///
476    /// ```
477    /// use minidom::Element;
478    ///
479    /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
480    ///
481    /// assert_eq!(elem.has_child("a", "other_ns"), true);
482    /// assert_eq!(elem.has_child("a", "ns"), true);
483    /// assert_eq!(elem.has_child("a", "inexistent_ns"), false);
484    /// assert_eq!(elem.has_child("b", "ns"), true);
485    /// assert_eq!(elem.has_child("b", "other_ns"), false);
486    /// assert_eq!(elem.has_child("b", "inexistent_ns"), false);
487    /// ```
488    pub fn has_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
489        self.get_child(name, namespace).is_some()
490    }
491}
492
493/// An iterator over references to children of an `Element`.
494pub struct Children<'a> {
495    iter: slice::Iter<'a, Node>,
496}
497
498impl<'a> Iterator for Children<'a> {
499    type Item = &'a Element;
500
501    fn next(&mut self) -> Option<&'a Element> {
502        while let Some(item) = self.iter.next() {
503            if let Node::Element(ref child) = *item {
504                return Some(child);
505            }
506        }
507        None
508    }
509}
510
511/// An iterator over mutable references to children of an `Element`.
512pub struct ChildrenMut<'a> {
513    iter: slice::IterMut<'a, Node>,
514}
515
516impl<'a> Iterator for ChildrenMut<'a> {
517    type Item = &'a mut Element;
518
519    fn next(&mut self) -> Option<&'a mut Element> {
520        while let Some(item) = self.iter.next() {
521            if let Node::Element(ref mut child) = *item {
522                return Some(child);
523            }
524        }
525        None
526    }
527}
528
529/// A builder for `Element`s.
530pub struct ElementBuilder {
531    root: Element,
532}
533
534impl ElementBuilder {
535    /// Sets the namespace.
536    pub fn ns<S: Into<String>>(mut self, namespace: S) -> ElementBuilder {
537        self.root.namespace = Some(namespace.into());
538        self
539    }
540
541    /// Sets an attribute.
542    pub fn attr<S: Into<String>, V: IntoAttributeValue>(mut self, name: S, value: V) -> ElementBuilder {
543        self.root.set_attr(name, value);
544        self
545    }
546
547    /// Appends anything implementing `IntoElements` into the tree.
548    pub fn append<T: IntoElements>(mut self, into: T) -> ElementBuilder {
549        {
550            let mut emitter = ElementEmitter::new(&mut self.root);
551            into.into_elements(&mut emitter);
552        }
553        self
554    }
555
556    /// Builds the `Element`.
557    pub fn build(self) -> Element {
558        self.root
559    }
560}
561
562#[test]
563fn test_element_new() {
564    let elem = Element::new( "name".to_owned()
565                           , Some("namespace".to_owned())
566                           , BTreeMap::from_iter(vec![ ("name".to_string(), "value".to_string()) ].into_iter() )
567                           , Vec::new() );
568
569    assert_eq!(elem.name(), "name");
570    assert_eq!(elem.ns(), Some("namespace"));
571    assert_eq!(elem.attr("name"), Some("value"));
572    assert_eq!(elem.attr("inexistent"), None);
573}