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. <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}