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