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::collections::btree_map;
  7
  8use std::fmt;
  9
 10use error::{Error, ErrorKind, Result};
 11
 12use xml::reader::{XmlEvent as ReaderEvent, EventReader};
 13use xml::writer::{XmlEvent as WriterEvent, EventWriter, EmitterConfig};
 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/// A node in an element tree.
 24#[derive(Clone, Debug, PartialEq, Eq)]
 25pub enum Node {
 26    /// An `Element`.
 27    Element(Element),
 28    /// A text node.
 29    Text(String),
 30}
 31
 32impl Node {
 33    /// Turns this into an `Element` if possible, else returns None.
 34    ///
 35    /// # Examples
 36    ///
 37    /// ```rust
 38    /// use minidom::Node;
 39    ///
 40    /// let elm = Node::Element("<meow />".parse().unwrap());
 41    /// let txt = Node::Text("meow".to_owned());
 42    ///
 43    /// assert_eq!(elm.as_element().unwrap().name(), "meow");
 44    /// assert_eq!(txt.as_element(), None);
 45    /// ```
 46    pub fn as_element(&self) -> Option<&Element> {
 47        match *self {
 48            Node::Element(ref e) => Some(e),
 49            Node::Text(_) => None,
 50        }
 51    }
 52
 53    /// Turns this into a `String` if possible, else returns None.
 54    ///
 55    /// # Examples
 56    ///
 57    /// ```rust
 58    /// use minidom::Node;
 59    ///
 60    /// let elm = Node::Element("<meow />".parse().unwrap());
 61    /// let txt = Node::Text("meow".to_owned());
 62    ///
 63    /// assert_eq!(elm.as_text(), None);
 64    /// assert_eq!(txt.as_text().unwrap(), "meow");
 65    /// ```
 66    pub fn as_text(&self) -> Option<&str> {
 67        match *self {
 68            Node::Element(_) => None,
 69            Node::Text(ref s) => Some(s),
 70        }
 71    }
 72}
 73
 74#[derive(Clone, PartialEq, Eq)]
 75/// A struct representing a DOM Element.
 76pub struct Element {
 77    name: String,
 78    namespace: Option<String>,
 79    attributes: BTreeMap<String, String>,
 80    children: Vec<Node>,
 81}
 82
 83impl<'a> From<&'a Element> for String {
 84    fn from(elem: &'a Element) -> String {
 85        let mut out = Vec::new();
 86        let config = EmitterConfig::new()
 87                    .write_document_declaration(false);
 88        elem.write_to(&mut EventWriter::new_with_config(&mut out, config)).unwrap();
 89        String::from_utf8(out).unwrap()
 90    }
 91}
 92
 93impl fmt::Debug for Element {
 94    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
 95        write!(fmt, "{}", String::from(self))?;
 96        Ok(())
 97    }
 98}
 99
100impl FromStr for Element {
101    type Err = Error;
102
103    fn from_str(s: &str) -> Result<Element> {
104        let mut reader = EventReader::new(Cursor::new(s));
105        Element::from_reader(&mut reader)
106    }
107}
108
109impl Element {
110    fn new(name: String, namespace: Option<String>, attributes: BTreeMap<String, String>, children: Vec<Node>) -> Element {
111        Element {
112            name: name,
113            namespace: namespace,
114            attributes: attributes,
115            children: children,
116        }
117    }
118
119    /// Return a builder for an `Element` with the given `name`.
120    ///
121    /// # Examples
122    ///
123    /// ```rust
124    /// use minidom::Element;
125    ///
126    /// let elem = Element::builder("name")
127    ///                    .ns("namespace")
128    ///                    .attr("name", "value")
129    ///                    .append("inner")
130    ///                    .build();
131    ///
132    /// assert_eq!(elem.name(), "name");
133    /// assert_eq!(elem.ns(), Some("namespace"));
134    /// assert_eq!(elem.attr("name"), Some("value"));
135    /// assert_eq!(elem.attr("inexistent"), None);
136    /// assert_eq!(elem.text(), "inner");
137    /// ```
138    pub fn builder<S: Into<String>>(name: S) -> ElementBuilder {
139        ElementBuilder {
140            root: Element::new(name.into(), None, BTreeMap::new(), Vec::new()),
141        }
142    }
143
144    /// Returns a bare minimum `Element` with this name.
145    ///
146    /// # Examples
147    ///
148    /// ```rust
149    /// use minidom::Element;
150    ///
151    /// let bare = Element::bare("name");
152    ///
153    /// assert_eq!(bare.name(), "name");
154    /// assert_eq!(bare.ns(), None);
155    /// assert_eq!(bare.attr("name"), None);
156    /// assert_eq!(bare.text(), "");
157    /// ```
158    pub fn bare<S: Into<String>>(name: S) -> Element {
159        Element {
160            name: name.into(),
161            namespace: None,
162            attributes: BTreeMap::new(),
163            children: Vec::new(),
164        }
165    }
166
167    /// Returns a reference to the name of this element.
168    pub fn name(&self) -> &str {
169        &self.name
170    }
171
172    /// Returns a reference to the namespace of this element, if it has one, else `None`.
173    pub fn ns(&self) -> Option<&str> {
174        self.namespace.as_ref()
175                      .map(String::as_ref)
176    }
177
178    /// Returns a reference to the value of the given attribute, if it exists, else `None`.
179    pub fn attr(&self, name: &str) -> Option<&str> {
180        if let Some(value) = self.attributes.get(name) {
181            return Some(value)
182        }
183        None
184    }
185
186    /// Returns an iterator over the attributes of this element.
187    ///
188    /// # Example
189    ///
190    /// ```rust
191    /// use minidom::Element;
192    ///
193    /// let elm: Element = "<elem a=\"b\" />".parse().unwrap();
194    ///
195    /// let mut iter = elm.attrs();
196    ///
197    /// assert_eq!(iter.next().unwrap(), ("a", "b"));
198    /// assert_eq!(iter.next(), None);
199    /// ```
200    pub fn attrs(&self) -> Attrs {
201        Attrs {
202            iter: self.attributes.iter(),
203        }
204    }
205
206    /// Returns an iterator over the attributes of this element, with the value being a mutable
207    /// reference.
208    pub fn attrs_mut(&mut self) -> AttrsMut {
209        AttrsMut {
210            iter: self.attributes.iter_mut(),
211        }
212    }
213
214    /// Modifies the value of an attribute.
215    pub fn set_attr<S: Into<String>, V: IntoAttributeValue>(&mut self, name: S, val: V) {
216        let name = name.into();
217        let val = val.into_attribute_value();
218
219        if let Some(value) = self.attributes.get_mut(&name) {
220            *value = val.expect("removing existing value via set_attr, this is not yet supported (TODO)"); // TODO
221            return;
222        }
223
224        if let Some(val) = val {
225            self.attributes.insert(name, val);
226        }
227    }
228
229    /// Returns whether the element has the given name and namespace.
230    ///
231    /// # Examples
232    ///
233    /// ```rust
234    /// use minidom::Element;
235    ///
236    /// let elem = Element::builder("name").ns("namespace").build();
237    ///
238    /// assert_eq!(elem.is("name", "namespace"), true);
239    /// assert_eq!(elem.is("name", "wrong"), false);
240    /// assert_eq!(elem.is("wrong", "namespace"), false);
241    /// assert_eq!(elem.is("wrong", "wrong"), false);
242    /// ```
243    pub fn is<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
244        let ns = self.namespace.as_ref().map(String::as_ref);
245        self.name == name.as_ref() && ns == Some(namespace.as_ref())
246    }
247
248    /// Parse a document from an `EventReader`.
249    pub fn from_reader<R: Read>(reader: &mut EventReader<R>) -> Result<Element> {
250        loop {
251            let e = reader.next()?;
252            match e {
253                ReaderEvent::StartElement { name, attributes, namespace } => {
254                    let attributes = attributes.into_iter()
255                                               .map(|o| {
256                                                    (match o.name.prefix {
257                                                        Some(prefix) => format!("{}:{}", prefix, o.name.local_name),
258                                                        None => o.name.local_name
259                                                    },
260                                                    o.value)
261                                                })
262                                               .collect();
263                    let ns = if let Some(ref prefix) = name.prefix {
264                        namespace.get(prefix)
265                    }
266                    else {
267                        namespace.get(NS_NO_PREFIX)
268                    }.map(|s| s.to_owned());
269
270                    let mut root = Element::new(name.local_name, ns, attributes, Vec::new());
271                    root.from_reader_inner(reader)?;
272                    return Ok(root);
273                },
274                ReaderEvent::EndDocument => {
275                    bail!(ErrorKind::EndOfDocument);
276                },
277                _ => () // TODO: may need more errors
278            }
279        }
280    }
281
282    #[cfg_attr(feature = "cargo-clippy", allow(wrong_self_convention))]
283    fn from_reader_inner<R: Read>(&mut self, reader: &mut EventReader<R>) -> Result<()> {
284        loop {
285            let e = reader.next()?;
286            match e {
287                ReaderEvent::StartElement { name, attributes, namespace } => {
288                    let attributes = attributes.into_iter()
289                                               .map(|o| {
290                                                    (match o.name.prefix {
291                                                        Some(prefix) => format!("{}:{}", prefix, o.name.local_name),
292                                                        None => o.name.local_name
293                                                    },
294                                                    o.value)
295                                                })
296                                               .collect();
297                    let ns = if let Some(ref prefix) = name.prefix {
298                        namespace.get(prefix)
299                    }
300                    else {
301                        namespace.get(NS_NO_PREFIX)
302                    }.map(|s| s.to_owned());
303                    let elem = Element::new(name.local_name, ns, attributes, Vec::with_capacity(1));
304                    let elem_ref = self.append_child(elem);
305                    elem_ref.from_reader_inner(reader)?;
306                },
307                ReaderEvent::EndElement { .. } => {
308                    // TODO: may want to check whether we're closing the correct element
309                    return Ok(());
310                },
311                ReaderEvent::Characters(s) | ReaderEvent::CData(s) => {
312                    self.append_text_node(s);
313                },
314                ReaderEvent::EndDocument => {
315                    bail!(ErrorKind::EndOfDocument);
316                },
317                _ => (), // TODO: may need to implement more
318            }
319        }
320    }
321
322    /// Output a document to an `EventWriter`.
323    pub fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<()> {
324        let name = if let Some(ref ns) = self.namespace {
325            Name::qualified(&self.name, ns, None)
326        }
327        else {
328            Name::local(&self.name)
329        };
330        let mut start = WriterEvent::start_element(name);
331        if let Some(ref ns) = self.namespace {
332            start = start.default_ns(ns.clone());
333        }
334        for attr in &self.attributes { // TODO: I think this could be done a lot more efficiently
335            start = start.attr(Name::local(attr.0), attr.1);
336        }
337        writer.write(start)?;
338        for child in &self.children {
339            match *child {
340                Node::Element(ref e) => {
341                    e.write_to(writer)?;
342                },
343                Node::Text(ref s) => {
344                    writer.write(WriterEvent::characters(s))?;
345                },
346            }
347        }
348        writer.write(WriterEvent::end_element())?;
349        Ok(())
350    }
351
352    /// Returns an iterator over references to every child node of this element.
353    ///
354    /// # Examples
355    ///
356    /// ```rust
357    /// use minidom::{Element, Node};
358    ///
359    /// let elem: Element = "<root>a<c1 />b<c2 />c</root>".parse().unwrap();
360    ///
361    /// let mut iter = elem.nodes();
362    ///
363    /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "a");
364    /// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c1");
365    /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "b");
366    /// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c2");
367    /// assert_eq!(iter.next().unwrap().as_text().unwrap(), "c");
368    /// assert_eq!(iter.next(), None);
369    /// ```
370    #[inline] pub fn nodes(&self) -> Nodes {
371        self.children.iter()
372    }
373
374    /// Returns an iterator over mutable references to every child node of this element.
375    #[inline] pub fn nodes_mut(&mut self) -> NodesMut {
376        self.children.iter_mut()
377    }
378
379    /// Returns an iterator over references to every child element of this element.
380    ///
381    /// # Examples
382    ///
383    /// ```rust
384    /// use minidom::Element;
385    ///
386    /// let elem: Element = "<root>hello<child1 />this<child2 />is<child3 />ignored</root>".parse().unwrap();
387    ///
388    /// let mut iter = elem.children();
389    /// assert_eq!(iter.next().unwrap().name(), "child1");
390    /// assert_eq!(iter.next().unwrap().name(), "child2");
391    /// assert_eq!(iter.next().unwrap().name(), "child3");
392    /// assert_eq!(iter.next(), None);
393    /// ```
394    #[inline] pub fn children(&self) -> Children {
395        Children {
396            iter: self.children.iter(),
397        }
398    }
399
400    /// Returns an iterator over mutable references to every child element of this element.
401    #[inline] pub fn children_mut(&mut self) -> ChildrenMut {
402        ChildrenMut {
403            iter: self.children.iter_mut(),
404        }
405    }
406
407    /// Returns an iterator over references to every text node of this element.
408    ///
409    /// # Examples
410    ///
411    /// ```rust
412    /// use minidom::Element;
413    ///
414    /// let elem: Element = "<root>hello<c /> world!</root>".parse().unwrap();
415    ///
416    /// let mut iter = elem.texts();
417    /// assert_eq!(iter.next().unwrap(), "hello");
418    /// assert_eq!(iter.next().unwrap(), " world!");
419    /// assert_eq!(iter.next(), None);
420    /// ```
421    #[inline] pub fn texts(&self) -> Texts {
422        Texts {
423            iter: self.children.iter(),
424        }
425    }
426
427    /// Returns an iterator over mutable references to every text node of this element.
428    #[inline] pub fn texts_mut(&mut self) -> TextsMut {
429        TextsMut {
430            iter: self.children.iter_mut(),
431        }
432    }
433
434    /// Appends a child node to the `Element`, returning the appended node.
435    ///
436    /// # Examples
437    ///
438    /// ```rust
439    /// use minidom::Element;
440    ///
441    /// let mut elem = Element::bare("root");
442    ///
443    /// assert_eq!(elem.children().count(), 0);
444    ///
445    /// elem.append_child(Element::bare("child"));
446    ///
447    /// {
448    ///     let mut iter = elem.children();
449    ///     assert_eq!(iter.next().unwrap().name(), "child");
450    ///     assert_eq!(iter.next(), None);
451    /// }
452    ///
453    /// let child = elem.append_child(Element::bare("new"));
454    ///
455    /// assert_eq!(child.name(), "new");
456    /// ```
457    pub fn append_child(&mut self, mut child: Element) -> &mut Element {
458        if child.namespace.is_none() && self.namespace.is_some() {
459            child.namespace = self.namespace.clone();
460            child.propagate_namespaces();
461        }
462        self.children.push(Node::Element(child));
463        if let Node::Element(ref mut cld) = *self.children.last_mut().unwrap() {
464            cld
465        }
466        else {
467            unreachable!()
468        }
469    }
470
471    fn propagate_namespaces(&mut self) {
472        let ns = self.namespace.clone();
473        for child in self.children_mut() {
474            if child.namespace.is_none() {
475                child.namespace = ns.clone();
476                child.propagate_namespaces();
477            }
478        }
479    }
480
481    /// Appends a text node to an `Element`.
482    ///
483    /// # Examples
484    ///
485    /// ```rust
486    /// use minidom::Element;
487    ///
488    /// let mut elem = Element::bare("node");
489    ///
490    /// assert_eq!(elem.text(), "");
491    ///
492    /// elem.append_text_node("text");
493    ///
494    /// assert_eq!(elem.text(), "text");
495    /// ```
496    pub fn append_text_node<S: Into<String>>(&mut self, child: S) {
497        self.children.push(Node::Text(child.into()));
498    }
499
500    /// Appends a node to an `Element`.
501    ///
502    /// # Examples
503    ///
504    /// ```rust
505    /// use minidom::{Element, Node};
506    ///
507    /// let mut elem = Element::bare("node");
508    ///
509    /// elem.append_node(Node::Text("hello".to_owned()));
510    ///
511    /// assert_eq!(elem.text(), "hello");
512    /// ```
513    pub fn append_node(&mut self, node: Node) {
514        self.children.push(node);
515    }
516
517    /// Returns the concatenation of all text nodes in the `Element`.
518    ///
519    /// # Examples
520    ///
521    /// ```rust
522    /// use minidom::Element;
523    ///
524    /// let elem: Element = "<node>hello,<split /> world!</node>".parse().unwrap();
525    ///
526    /// assert_eq!(elem.text(), "hello, world!");
527    /// ```
528    pub fn text(&self) -> String {
529        self.texts().fold(String::new(), |ret, new| ret + new)
530    }
531
532    /// Returns a reference to the first child element with the specific name and namespace, if it
533    /// exists in the direct descendants of this `Element`, else returns `None`.
534    ///
535    /// # Examples
536    ///
537    /// ```rust
538    /// use minidom::Element;
539    ///
540    /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
541    ///
542    /// assert!(elem.get_child("a", "ns").unwrap().is("a", "ns"));
543    /// assert!(elem.get_child("a", "other_ns").unwrap().is("a", "other_ns"));
544    /// assert!(elem.get_child("b", "ns").unwrap().is("b", "ns"));
545    /// assert_eq!(elem.get_child("c", "ns"), None);
546    /// assert_eq!(elem.get_child("b", "other_ns"), None);
547    /// assert_eq!(elem.get_child("a", "inexistent_ns"), None);
548    /// ```
549    pub fn get_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> Option<&Element> {
550        for fork in &self.children {
551            if let Node::Element(ref e) = *fork {
552                if e.is(name.as_ref(), namespace.as_ref()) {
553                    return Some(e);
554                }
555            }
556        }
557        None
558    }
559
560    /// Returns a mutable reference to the first child element with the specific name and namespace,
561    /// if it exists in the direct descendants of this `Element`, else returns `None`.
562    pub fn get_child_mut<N: AsRef<str>, NS: AsRef<str>>(&mut self, name: N, namespace: NS) -> Option<&mut Element> {
563        for fork in &mut self.children {
564            if let Node::Element(ref mut e) = *fork {
565                if e.is(name.as_ref(), namespace.as_ref()) {
566                    return Some(e);
567                }
568            }
569        }
570        None
571    }
572
573    /// Returns whether a specific child with this name and namespace exists in the direct
574    /// descendants of the `Element`.
575    ///
576    /// # Examples
577    ///
578    /// ```rust
579    /// use minidom::Element;
580    ///
581    /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
582    ///
583    /// assert_eq!(elem.has_child("a", "other_ns"), true);
584    /// assert_eq!(elem.has_child("a", "ns"), true);
585    /// assert_eq!(elem.has_child("a", "inexistent_ns"), false);
586    /// assert_eq!(elem.has_child("b", "ns"), true);
587    /// assert_eq!(elem.has_child("b", "other_ns"), false);
588    /// assert_eq!(elem.has_child("b", "inexistent_ns"), false);
589    /// ```
590    pub fn has_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
591        self.get_child(name, namespace).is_some()
592    }
593}
594
595/// An iterator over references to child elements of an `Element`.
596pub struct Children<'a> {
597    iter: slice::Iter<'a, Node>,
598}
599
600impl<'a> Iterator for Children<'a> {
601    type Item = &'a Element;
602
603    fn next(&mut self) -> Option<&'a Element> {
604        for item in &mut self.iter {
605            if let Node::Element(ref child) = *item {
606                return Some(child);
607            }
608        }
609        None
610    }
611}
612
613/// An iterator over mutable references to child elements of an `Element`.
614pub struct ChildrenMut<'a> {
615    iter: slice::IterMut<'a, Node>,
616}
617
618impl<'a> Iterator for ChildrenMut<'a> {
619    type Item = &'a mut Element;
620
621    fn next(&mut self) -> Option<&'a mut Element> {
622        for item in &mut self.iter {
623            if let Node::Element(ref mut child) = *item {
624                return Some(child);
625            }
626        }
627        None
628    }
629}
630
631/// An iterator over references to child text nodes of an `Element`.
632pub struct Texts<'a> {
633    iter: slice::Iter<'a, Node>,
634}
635
636impl<'a> Iterator for Texts<'a> {
637    type Item = &'a str;
638
639    fn next(&mut self) -> Option<&'a str> {
640        for item in &mut self.iter {
641            if let Node::Text(ref child) = *item {
642                return Some(child);
643            }
644        }
645        None
646    }
647}
648
649/// An iterator over mutable references to child text nodes of an `Element`.
650pub struct TextsMut<'a> {
651    iter: slice::IterMut<'a, Node>,
652}
653
654impl<'a> Iterator for TextsMut<'a> {
655    type Item = &'a mut String;
656
657    fn next(&mut self) -> Option<&'a mut String> {
658        for item in &mut self.iter {
659            if let Node::Text(ref mut child) = *item {
660                return Some(child);
661            }
662        }
663        None
664    }
665}
666
667/// An iterator over references to all child nodes of an `Element`.
668pub type Nodes<'a> = slice::Iter<'a, Node>;
669
670/// An iterator over mutable references to all child nodes of an `Element`.
671pub type NodesMut<'a> = slice::IterMut<'a, Node>;
672
673/// An iterator over the attributes of an `Element`.
674pub struct Attrs<'a> {
675    iter: btree_map::Iter<'a, String, String>,
676}
677
678impl<'a> Iterator for Attrs<'a> {
679    type Item = (&'a str, &'a str);
680
681    fn next(&mut self) -> Option<Self::Item> {
682        self.iter.next().map(|(x, y)| (x.as_ref(), y.as_ref()))
683    }
684}
685
686/// An iterator over the attributes of an `Element`, with the values mutable.
687pub struct AttrsMut<'a> {
688    iter: btree_map::IterMut<'a, String, String>,
689}
690
691impl<'a> Iterator for AttrsMut<'a> {
692    type Item = (&'a str, &'a mut String);
693
694    fn next(&mut self) -> Option<Self::Item> {
695        self.iter.next().map(|(x, y)| (x.as_ref(), y))
696    }
697}
698
699/// A builder for `Element`s.
700pub struct ElementBuilder {
701    root: Element,
702}
703
704impl ElementBuilder {
705    /// Sets the namespace.
706    pub fn ns<S: Into<String>>(mut self, namespace: S) -> ElementBuilder {
707        self.root.namespace = Some(namespace.into());
708        self
709    }
710
711    /// Sets an attribute.
712    pub fn attr<S: Into<String>, V: IntoAttributeValue>(mut self, name: S, value: V) -> ElementBuilder {
713        self.root.set_attr(name, value);
714        self
715    }
716
717    /// Appends anything implementing `IntoElements` into the tree.
718    pub fn append<T: IntoElements>(mut self, into: T) -> ElementBuilder {
719        {
720            let mut emitter = ElementEmitter::new(&mut self.root);
721            into.into_elements(&mut emitter);
722        }
723        self
724    }
725
726    /// Builds the `Element`.
727    pub fn build(self) -> Element {
728        self.root
729    }
730}
731
732#[test]
733fn test_element_new() {
734    use std::iter::FromIterator;
735
736    let elem = Element::new( "name".to_owned()
737                           , Some("namespace".to_owned())
738                           , BTreeMap::from_iter(vec![ ("name".to_string(), "value".to_string()) ].into_iter() )
739                           , Vec::new() );
740
741    assert_eq!(elem.name(), "name");
742    assert_eq!(elem.ns(), Some("namespace"));
743    assert_eq!(elem.attr("name"), Some("value"));
744    assert_eq!(elem.attr("inexistent"), None);
745}