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