lib.rs

  1//! A minimal DOM crate built on top of xml-rs.
  2//!
  3//! This library exports an `Element` struct which represents a DOM tree.
  4//!
  5//! # Example
  6//!
  7//! Run with `cargo run --example articles`. Located in `examples/articles.rs`.
  8//!
  9//! ```rust,ignore
 10//! extern crate minidom;
 11//!
 12//! use minidom::Element;
 13//!
 14//! const DATA: &'static str = r#"<articles xmlns="article">
 15//!     <article>
 16//!         <title>10 Terrible Bugs You Would NEVER Believe Happened</title>
 17//!         <body>
 18//!             Rust fixed them all. &lt;3
 19//!         </body>
 20//!     </article>
 21//!     <article>
 22//!         <title>BREAKING NEWS: Physical Bug Jumps Out Of Programmer's Screen</title>
 23//!         <body>
 24//!             Just kidding!
 25//!         </body>
 26//!     </article>
 27//! </articles>"#;
 28//!
 29//! const ARTICLE_NS: &'static str = "article";
 30//!
 31//! #[derive(Debug)]
 32//! pub struct Article {
 33//!     title: String,
 34//!     body: String,
 35//! }
 36//!
 37//! fn main() {
 38//!     let root: Element = DATA.parse().unwrap();
 39//!
 40//!     let mut articles: Vec<Article> = Vec::new();
 41//!
 42//!     for child in root.children() {
 43//!         if child.is("article", ARTICLE_NS) {
 44//!             let title = child.get_child("title", ARTICLE_NS).unwrap().text();
 45//!             let body = child.get_child("body", ARTICLE_NS).unwrap().text();
 46//!             articles.push(Article {
 47//!                 title: title,
 48//!                 body: body.trim().to_owned(),
 49//!             });
 50//!         }
 51//!     }
 52//!
 53//!     println!("{:?}", articles);
 54//! }
 55//! ```
 56//!
 57//! # Usage
 58//!
 59//! To use `minidom`, add this to your `Cargo.toml`:
 60//!
 61//! ```toml,ignore
 62//! [dependencies.minidom]
 63//! git = "https://gitlab.com/lumi/minidom-rs.git"
 64//! ```
 65
 66extern crate xml;
 67
 68mod error;
 69
 70mod attribute;
 71
 72use std::io::prelude::*;
 73use std::io::Cursor;
 74
 75use std::convert::AsRef;
 76
 77use std::iter::Iterator;
 78
 79use std::slice;
 80
 81use std::fmt;
 82
 83use std::str::FromStr;
 84
 85use xml::reader::{XmlEvent as ReaderEvent, EventReader};
 86use xml::writer::{XmlEvent as WriterEvent, EventWriter};
 87use xml::name::Name;
 88use xml::namespace::NS_NO_PREFIX;
 89
 90pub use error::Error;
 91
 92pub use attribute::Attribute;
 93
 94#[derive(Clone, PartialEq, Eq)]
 95/// A struct representing a DOM Element.
 96pub struct Element {
 97    name: String,
 98    namespace: Option<String>,
 99    attributes: Vec<Attribute>,
100    children: Vec<Fork>,
101}
102
103impl fmt::Debug for Element {
104    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
105        if let Some(ref ns) = self.namespace {
106            write!(fmt, "<{{{}}}{}", ns, self.name)?;
107        }
108        else {
109            write!(fmt, "<{}", self.name)?;
110        }
111        for attr in &self.attributes {
112            write!(fmt, " {}", attr)?;
113        }
114        write!(fmt, ">")?;
115        for child in &self.children {
116            match *child {
117                Fork::Element(ref e) => {
118                    write!(fmt, "{:?}", e)?;
119                },
120                Fork::Text(ref s) => {
121                    write!(fmt, "{}", s)?;
122                },
123            }
124        }
125        write!(fmt, "</{}>", self.name)?;
126        Ok(())
127    }
128}
129
130impl FromStr for Element {
131    type Err = Error;
132
133    fn from_str(s: &str) -> Result<Element, Error> {
134        let mut reader = EventReader::new(Cursor::new(s));
135        Element::from_reader(&mut reader)
136    }
137}
138
139#[derive(Clone, Debug, PartialEq, Eq)]
140enum Fork {
141    Element(Element),
142    Text(String),
143}
144
145impl Element {
146    /// Constructs a new `Element` with the given `name`, `namespace` and `attributes`.
147    ///
148    /// You probably should be using `Element::builder` instead of this.
149    ///
150    /// # Examples
151    ///
152    /// ```
153    /// use minidom::{Element, Attribute};
154    ///
155    /// let elem = Element::new( "name".to_owned()
156    ///                        , Some("namespace".to_owned())
157    ///                        , vec![ Attribute::new("name", "value") ] );
158    ///
159    /// assert_eq!(elem.name(), "name");
160    /// assert_eq!(elem.ns(), Some("namespace"));
161    /// assert_eq!(elem.attr("name"), Some("value"));
162    /// assert_eq!(elem.attr("inexistent"), None);
163    /// ```
164    pub fn new(name: String, namespace: Option<String>, attributes: Vec<Attribute>) -> Element {
165        Element {
166            name: name,
167            namespace: namespace,
168            attributes: attributes,
169            children: Vec::new(),
170        }
171    }
172
173    /// Return a builder for an `Element` with the given `name`.
174    ///
175    /// # Examples
176    ///
177    /// ```
178    /// use minidom::Element;
179    ///
180    /// let elem = Element::builder("name")
181    ///                    .ns("namespace")
182    ///                    .attr("name", "value")
183    ///                    .text("inner")
184    ///                    .build();
185    ///
186    /// assert_eq!(elem.name(), "name");
187    /// assert_eq!(elem.ns(), Some("namespace"));
188    /// assert_eq!(elem.attr("name"), Some("value"));
189    /// assert_eq!(elem.attr("inexistent"), None);
190    /// assert_eq!(elem.text(), "inner");
191    /// ```
192    pub fn builder<S: Into<String>>(name: S) -> ElementBuilder {
193        ElementBuilder {
194            name: name.into(),
195            text: None,
196            namespace: None,
197            attributes: Vec::new(),
198        }
199    }
200
201    /// Returns a bare minimum `Element` with this name.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// use minidom::Element;
207    ///
208    /// let bare = Element::bare("name");
209    ///
210    /// assert_eq!(bare.name(), "name");
211    /// assert_eq!(bare.ns(), None);
212    /// assert_eq!(bare.attr("name"), None);
213    /// assert_eq!(bare.text(), "");
214    /// ```
215    pub fn bare<S: Into<String>>(name: S) -> Element {
216        Element {
217            name: name.into(),
218            namespace: None,
219            attributes: Vec::new(),
220            children: Vec::new(),
221        }
222    }
223
224    /// Returns a reference to the name of this element.
225    pub fn name(&self) -> &str {
226        &self.name
227    }
228
229    /// Returns a reference to the namespace of this element, if it has one, else `None`.
230    pub fn ns(&self) -> Option<&str> {
231        self.namespace.as_ref()
232                      .map(String::as_ref)
233    }
234
235    /// Returns a reference to the value of the given attribute, if it exists, else `None`.
236    pub fn attr(&self, name: &str) -> Option<&str> {
237        for attr in &self.attributes {
238            if attr.name == name {
239                return Some(&attr.value);
240            }
241        }
242        None
243    }
244
245    /// Returns whether the element has the given name and namespace.
246    ///
247    /// # Examples
248    ///
249    /// ```
250    /// use minidom::Element;
251    ///
252    /// let elem = Element::builder("name").ns("namespace").build();
253    ///
254    /// assert_eq!(elem.is("name", "namespace"), true);
255    /// assert_eq!(elem.is("name", "wrong"), false);
256    /// assert_eq!(elem.is("wrong", "namespace"), false);
257    /// assert_eq!(elem.is("wrong", "wrong"), false);
258    /// ```
259    pub fn is<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
260        let ns = self.namespace.as_ref().map(String::as_ref);
261        self.name == name.as_ref() && ns == Some(namespace.as_ref())
262    }
263
264    pub fn from_reader<R: Read>(reader: &mut EventReader<R>) -> Result<Element, Error> {
265        loop {
266            let e = reader.next()?;
267            match e {
268                ReaderEvent::StartElement { name, attributes, namespace } => {
269                    let attributes = attributes.into_iter()
270                                               .map(|o| Attribute::new(o.name.local_name, o.value))
271                                               .collect();
272                    let ns = if let Some(ref prefix) = name.prefix {
273                        namespace.get(prefix)
274                    }
275                    else {
276                        namespace.get(NS_NO_PREFIX)
277                    }.map(|s| s.to_owned());
278                    let mut root = Element::new(name.local_name, ns, attributes);
279                    root.from_reader_inner(reader)?;
280                    return Ok(root);
281                },
282                ReaderEvent::EndDocument => {
283                    return Err(Error::EndOfDocument);
284                },
285                _ => () // TODO: may need more errors
286            }
287        }
288    }
289
290    fn from_reader_inner<R: Read>(&mut self, reader: &mut EventReader<R>) -> Result<(), Error> {
291        loop {
292            let e = reader.next()?;
293            match e {
294                ReaderEvent::StartElement { name, attributes, namespace } => {
295                    let attributes = attributes.into_iter()
296                                               .map(|o| Attribute::new(o.name.local_name, o.value))
297                                               .collect();
298                    let ns = if let Some(ref prefix) = name.prefix {
299                        namespace.get(prefix)
300                    }
301                    else {
302                        namespace.get(NS_NO_PREFIX)
303                    }.map(|s| s.to_owned());
304                    let elem = Element::new(name.local_name, ns, attributes);
305                    let elem_ref = self.append_child(elem);
306                    elem_ref.from_reader_inner(reader)?;
307                },
308                ReaderEvent::EndElement { .. } => {
309                    // TODO: may want to check whether we're closing the correct element
310                    return Ok(());
311                },
312                ReaderEvent::Characters(s) => {
313                    self.append_text_node(s);
314                },
315                ReaderEvent::CData(s) => {
316                    self.append_text_node(s);
317                },
318                ReaderEvent::EndDocument => {
319                    return Err(Error::EndOfDocument);
320                },
321                _ => (), // TODO: may need to implement more
322            }
323        }
324    }
325
326    pub fn write_to<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<(), Error> {
327        let name = if let Some(ref ns) = self.namespace {
328            Name::qualified(&self.name, &ns, None)
329        }
330        else {
331            Name::local(&self.name)
332        };
333        let mut start = WriterEvent::start_element(name);
334        if let Some(ref ns) = self.namespace {
335            start = start.default_ns(ns.as_ref());
336        }
337        for attr in &self.attributes { // TODO: I think this could be done a lot more efficiently
338            start = start.attr(Name::local(&attr.name), &attr.value);
339        }
340        writer.write(start)?;
341        for child in &self.children {
342            match *child {
343                Fork::Element(ref e) => {
344                    e.write_to(writer)?;
345                },
346                Fork::Text(ref s) => {
347                    writer.write(WriterEvent::characters(s))?;
348                },
349            }
350        }
351        writer.write(WriterEvent::end_element())?;
352        Ok(())
353    }
354
355    /// Returns an iterator over references to the children of this element.
356    ///
357    /// # Examples
358    ///
359    /// ```
360    /// use minidom::Element;
361    ///
362    /// let elem: Element = "<root><child1 /><child2 /><child3 /></root>".parse().unwrap();
363    ///
364    /// let mut iter = elem.children();
365    /// assert_eq!(iter.next().unwrap().name(), "child1");
366    /// assert_eq!(iter.next().unwrap().name(), "child2");
367    /// assert_eq!(iter.next().unwrap().name(), "child3");
368    /// assert_eq!(iter.next(), None);
369    /// ```
370    pub fn children<'a>(&'a self) -> Children<'a> {
371        Children {
372            iter: self.children.iter(),
373        }
374    }
375
376    /// Returns an iterator over mutable references to the children of this element.
377    pub fn children_mut<'a>(&'a mut self) -> ChildrenMut<'a> {
378        ChildrenMut {
379            iter: self.children.iter_mut(),
380        }
381    }
382
383    /// Appends a child node to the `Element`, returning the appended node.
384    ///
385    /// # Examples
386    ///
387    /// ```
388    /// use minidom::Element;
389    ///
390    /// let mut elem = Element::bare("root");
391    ///
392    /// assert_eq!(elem.children().count(), 0);
393    ///
394    /// elem.append_child(Element::bare("child"));
395    ///
396    /// {
397    ///     let mut iter = elem.children();
398    ///     assert_eq!(iter.next().unwrap().name(), "child");
399    ///     assert_eq!(iter.next(), None);
400    /// }
401    ///
402    /// let child = elem.append_child(Element::bare("new"));
403    ///
404    /// assert_eq!(child.name(), "new");
405    /// ```
406    pub fn append_child(&mut self, mut child: Element) -> &mut Element {
407        if child.namespace.is_none() {
408            child.namespace = self.namespace.clone();
409        }
410        self.children.push(Fork::Element(child));
411        if let Fork::Element(ref mut cld) = *self.children.last_mut().unwrap() {
412            cld
413        }
414        else {
415            unreachable!()
416        }
417    }
418
419    /// Appends a text node to an `Element`.
420    ///
421    /// # Examples
422    ///
423    /// ```
424    /// use minidom::Element;
425    ///
426    /// let mut elem = Element::bare("node");
427    ///
428    /// assert_eq!(elem.text(), "");
429    ///
430    /// elem.append_text_node("text");
431    ///
432    /// assert_eq!(elem.text(), "text");
433    /// ```
434    pub fn append_text_node<S: Into<String>>(&mut self, child: S) {
435        self.children.push(Fork::Text(child.into()));
436    }
437
438    /// Returns the concatenation of all text nodes in the `Element`.
439    ///
440    /// # Examples
441    ///
442    /// ```
443    /// use minidom::Element;
444    ///
445    /// let elem: Element = "<node>hello, world!</node>".parse().unwrap();
446    ///
447    /// assert_eq!(elem.text(), "hello, world!");
448    /// ```
449    pub fn text(&self) -> String {
450        let mut ret = String::new();
451        for fork in &self.children {
452            if let Fork::Text(ref s) = *fork {
453                ret += s;
454            }
455        }
456        ret
457    }
458
459    /// Returns a reference to the first child element with the specific name and namespace, if it
460    /// exists in the direct descendants of this `Element`, else returns `None`.
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!(elem.get_child("a", "ns").unwrap().is("a", "ns"));
470    /// assert!(elem.get_child("a", "other_ns").unwrap().is("a", "other_ns"));
471    /// assert!(elem.get_child("b", "ns").unwrap().is("b", "ns"));
472    /// assert_eq!(elem.get_child("c", "ns"), None);
473    /// assert_eq!(elem.get_child("b", "other_ns"), None);
474    /// assert_eq!(elem.get_child("a", "inexistent_ns"), None);
475    /// ```
476    pub fn get_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> Option<&Element> {
477        for fork in &self.children {
478            if let Fork::Element(ref e) = *fork {
479                if e.is(name.as_ref(), namespace.as_ref()) {
480                    return Some(e);
481                }
482            }
483        }
484        None
485    }
486
487    /// Returns a mutable reference to the first child element with the specific name and namespace,
488    /// if it exists in the direct descendants of this `Element`, else returns `None`.
489    pub fn get_child_mut<N: AsRef<str>, NS: AsRef<str>>(&mut self, name: N, namespace: NS) -> Option<&mut Element> {
490        for fork in &mut self.children {
491            if let Fork::Element(ref mut e) = *fork {
492                if e.is(name.as_ref(), namespace.as_ref()) {
493                    return Some(e);
494                }
495            }
496        }
497        None
498    }
499
500    /// Returns whether a specific child with this name and namespace exists in the direct
501    /// descendants of the `Element`.
502    ///
503    /// # Examples
504    ///
505    /// ```
506    /// use minidom::Element;
507    ///
508    /// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
509    ///
510    /// assert_eq!(elem.has_child("a", "other_ns"), true);
511    /// assert_eq!(elem.has_child("a", "ns"), true);
512    /// assert_eq!(elem.has_child("a", "inexistent_ns"), false);
513    /// assert_eq!(elem.has_child("b", "ns"), true);
514    /// assert_eq!(elem.has_child("b", "other_ns"), false);
515    /// assert_eq!(elem.has_child("b", "inexistent_ns"), false);
516    /// ```
517    pub fn has_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
518        self.get_child(name, namespace).is_some()
519    }
520}
521
522/// An iterator over references to children of an `Element`.
523pub struct Children<'a> {
524    iter: slice::Iter<'a, Fork>,
525}
526
527impl<'a> Iterator for Children<'a> {
528    type Item = &'a Element;
529
530    fn next(&mut self) -> Option<&'a Element> {
531        while let Some(item) = self.iter.next() {
532            if let Fork::Element(ref child) = *item {
533                return Some(child);
534            }
535        }
536        None
537    }
538}
539
540/// An iterator over mutable references to children of an `Element`.
541pub struct ChildrenMut<'a> {
542    iter: slice::IterMut<'a, Fork>,
543}
544
545impl<'a> Iterator for ChildrenMut<'a> {
546    type Item = &'a mut Element;
547
548    fn next(&mut self) -> Option<&'a mut Element> {
549        while let Some(item) = self.iter.next() {
550            if let Fork::Element(ref mut child) = *item {
551                return Some(child);
552            }
553        }
554        None
555    }
556}
557
558/// A builder for `Element`s.
559pub struct ElementBuilder {
560    name: String,
561    text: Option<String>,
562    namespace: Option<String>,
563    attributes: Vec<Attribute>,
564}
565
566impl ElementBuilder {
567    /// Sets the namespace.
568    pub fn ns<S: Into<String>>(mut self, namespace: S) -> ElementBuilder {
569        self.namespace = Some(namespace.into());
570        self
571    }
572
573    /// Sets an attribute.
574    pub fn attr<S: Into<String>, V: Into<String>>(mut self, name: S, value: V) -> ElementBuilder {
575        self.attributes.push(Attribute::new(name, value));
576        self
577    }
578
579    /// Sets the inner text.
580    pub fn text<S: Into<String>>(mut self, text: S) -> ElementBuilder {
581        self.text = Some(text.into());
582        self
583    }
584
585    /// Builds the `Element`.
586    pub fn build(self) -> Element {
587        let mut elem = Element::new(self.name, self.namespace, self.attributes);
588        if let Some(text) = self.text {
589            elem.append_text_node(text);
590        }
591        elem
592    }
593}
594
595#[cfg(test)]
596mod tests {
597    use super::*;
598
599    use xml::reader::EventReader;
600    use xml::writer::EventWriter;
601
602    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>"#;
603
604    fn build_test_tree() -> Element {
605        let mut root = Element::builder("root")
606                               .ns("root_ns")
607                               .attr("a", "b")
608                               .build();
609        root.append_text_node("meow");
610        let child = Element::builder("child")
611                            .attr("c", "d")
612                            .build();
613        root.append_child(child);
614        let other_child = Element::builder("child")
615                                  .ns("child_ns")
616                                  .attr("d", "e")
617                                  .build();
618        root.append_child(other_child);
619        root.append_text_node("nya");
620        root
621    }
622
623    #[test]
624    fn reader_works() {
625        use std::io::Cursor;
626        let mut reader = EventReader::new(Cursor::new(TEST_STRING));
627        assert_eq!(Element::from_reader(&mut reader).unwrap(), build_test_tree());
628    }
629
630    #[test]
631    fn writer_works() {
632        let root = build_test_tree();
633        let mut out = Vec::new();
634        {
635            let mut writer = EventWriter::new(&mut out);
636            root.write_to(&mut writer).unwrap();
637        }
638        assert_eq!(String::from_utf8(out).unwrap(), TEST_STRING);
639    }
640
641    #[test]
642    fn builder_works() {
643        let elem = Element::builder("a")
644                           .ns("b")
645                           .attr("c", "d")
646                           .text("e")
647                           .build();
648        assert_eq!(elem.name(), "a");
649        assert_eq!(elem.ns(), Some("b"));
650        assert_eq!(elem.attr("c"), Some("d"));
651        assert_eq!(elem.attr("x"), None);
652        assert_eq!(elem.text(), "e");
653        assert!(elem.is("a", "b"));
654    }
655
656    #[test]
657    fn children_iter_works() {
658        let root = build_test_tree();
659        let mut iter = root.children();
660        assert!(iter.next().unwrap().is("child", "root_ns"));
661        assert!(iter.next().unwrap().is("child", "child_ns"));
662        assert_eq!(iter.next(), None);
663    }
664
665    #[test]
666    fn get_child_works() {
667        let root = build_test_tree();
668        assert_eq!(root.get_child("child", "inexistent_ns"), None);
669        assert_eq!(root.get_child("not_a_child", "root_ns"), None);
670        assert!(root.get_child("child", "root_ns").unwrap().is("child", "root_ns"));
671        assert!(root.get_child("child", "child_ns").unwrap().is("child", "child_ns"));
672        assert_eq!(root.get_child("child", "root_ns").unwrap().attr("c"), Some("d"));
673        assert_eq!(root.get_child("child", "child_ns").unwrap().attr("d"), Some("e"));
674    }
675}