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