Add iterators over attributes, nodes and text nodes. Clean up lots of code. Add as_element and as_text on Node. Add some inline annotations.
This commit is contained in:
parent
33f9dee31f
commit
83d80dd235
1 changed files with 227 additions and 41 deletions
268
src/element.rs
268
src/element.rs
|
@ -3,6 +3,7 @@
|
|||
use std::io::prelude::*;
|
||||
use std::io::Cursor;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
|
@ -19,6 +20,57 @@ use std::slice;
|
|||
|
||||
use convert::{IntoElements, IntoAttributeValue, ElementEmitter};
|
||||
|
||||
/// A node in an element tree.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Node {
|
||||
/// An `Element`.
|
||||
Element(Element),
|
||||
/// A text node.
|
||||
Text(String),
|
||||
}
|
||||
|
||||
impl Node {
|
||||
/// Turns this into an `Element` if possible, else returns None.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Node;
|
||||
///
|
||||
/// let elm = Node::Element("<meow />".parse().unwrap());
|
||||
/// let txt = Node::Text("meow".to_owned());
|
||||
///
|
||||
/// assert_eq!(elm.as_element().unwrap().name(), "meow");
|
||||
/// assert_eq!(txt.as_element(), None);
|
||||
/// ```
|
||||
pub fn as_element<'a>(&'a self) -> Option<&'a Element> {
|
||||
match *self {
|
||||
Node::Element(ref e) => Some(e),
|
||||
Node::Text(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns this into a `String` if possible, else returns None.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Node;
|
||||
///
|
||||
/// let elm = Node::Element("<meow />".parse().unwrap());
|
||||
/// let txt = Node::Text("meow".to_owned());
|
||||
///
|
||||
/// assert_eq!(elm.as_text(), None);
|
||||
/// assert_eq!(txt.as_text().unwrap(), "meow");
|
||||
/// ```
|
||||
pub fn as_text<'a>(&'a self) -> Option<&'a str> {
|
||||
match *self {
|
||||
Node::Element(_) => None,
|
||||
Node::Text(ref s) => Some(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
/// A struct representing a DOM Element.
|
||||
pub struct Element {
|
||||
|
@ -28,7 +80,6 @@ pub struct Element {
|
|||
children: Vec<Node>,
|
||||
}
|
||||
|
||||
|
||||
impl<'a> From<&'a Element> for String {
|
||||
fn from(elem: &'a Element) -> String {
|
||||
let mut out = Vec::new();
|
||||
|
@ -55,15 +106,6 @@ impl FromStr for Element {
|
|||
}
|
||||
}
|
||||
|
||||
/// A node in an element tree.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Node {
|
||||
/// An `Element`.
|
||||
Element(Element),
|
||||
/// A text node.
|
||||
Text(String),
|
||||
}
|
||||
|
||||
impl Element {
|
||||
fn new(name: String, namespace: Option<String>, attributes: BTreeMap<String, String>, children: Vec<Node>) -> Element {
|
||||
Element {
|
||||
|
@ -78,7 +120,7 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elem = Element::builder("name")
|
||||
|
@ -103,7 +145,7 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let bare = Element::bare("name");
|
||||
|
@ -141,6 +183,34 @@ impl Element {
|
|||
None
|
||||
}
|
||||
|
||||
/// Returns an iterator over the attributes of this element.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elm: Element = "<elem a=\"b\" />".parse().unwrap();
|
||||
///
|
||||
/// let mut iter = elm.attrs();
|
||||
///
|
||||
/// assert_eq!(iter.next().unwrap(), ("a", "b"));
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
pub fn attrs<'a>(&'a self) -> Attrs<'a> {
|
||||
Attrs {
|
||||
iter: self.attributes.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the attributes of this element, with the value being a mutable
|
||||
/// reference.
|
||||
pub fn attrs_mut<'a>(&'a mut self) -> AttrsMut<'a> {
|
||||
AttrsMut {
|
||||
iter: self.attributes.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies the value of an attribute.
|
||||
pub fn set_attr<S: Into<String>, V: IntoAttributeValue>(&mut self, name: S, val: V) {
|
||||
let name = name.into();
|
||||
|
@ -160,7 +230,7 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elem = Element::builder("name").ns("namespace").build();
|
||||
|
@ -281,14 +351,41 @@ impl Element {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns an iterator over references to the children of this element.
|
||||
/// Returns an iterator over references to every child node of this element.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::{Element, Node};
|
||||
///
|
||||
/// let elem: Element = "<root>a<c1 />b<c2 />c</root>".parse().unwrap();
|
||||
///
|
||||
/// let mut iter = elem.nodes();
|
||||
///
|
||||
/// assert_eq!(iter.next().unwrap().as_text().unwrap(), "a");
|
||||
/// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c1");
|
||||
/// assert_eq!(iter.next().unwrap().as_text().unwrap(), "b");
|
||||
/// assert_eq!(iter.next().unwrap().as_element().unwrap().name(), "c2");
|
||||
/// assert_eq!(iter.next().unwrap().as_text().unwrap(), "c");
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[inline] pub fn nodes<'a>(&'a self) -> Nodes<'a> {
|
||||
self.children.iter()
|
||||
}
|
||||
|
||||
/// Returns an iterator over mutable references to every child node of this element.
|
||||
#[inline] pub fn nodes_mut<'a>(&'a mut self) -> NodesMut<'a> {
|
||||
self.children.iter_mut()
|
||||
}
|
||||
|
||||
/// Returns an iterator over references to every child element of this element.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elem: Element = "<root><child1 /><child2 /><child3 /></root>".parse().unwrap();
|
||||
/// let elem: Element = "<root>hello<child1 />this<child2 />is<child3 />ignored</root>".parse().unwrap();
|
||||
///
|
||||
/// let mut iter = elem.children();
|
||||
/// assert_eq!(iter.next().unwrap().name(), "child1");
|
||||
|
@ -296,26 +393,43 @@ impl Element {
|
|||
/// assert_eq!(iter.next().unwrap().name(), "child3");
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
pub fn children<'a>(&'a self) -> Children<'a> {
|
||||
#[inline] pub fn children<'a>(&'a self) -> Children<'a> {
|
||||
Children {
|
||||
iter: self.children.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over mutable references to the children of this element.
|
||||
pub fn children_mut<'a>(&'a mut self) -> ChildrenMut<'a> {
|
||||
/// Returns an iterator over mutable references to every child element of this element.
|
||||
#[inline] pub fn children_mut<'a>(&'a mut self) -> ChildrenMut<'a> {
|
||||
ChildrenMut {
|
||||
iter: self.children.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_namespaces(&mut self) {
|
||||
let ns = self.namespace.clone();
|
||||
for child in self.children_mut() {
|
||||
if child.namespace.is_none() {
|
||||
child.namespace = ns.clone();
|
||||
child.propagate_namespaces();
|
||||
}
|
||||
/// Returns an iterator over references to every text node of this element.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elem: Element = "<root>hello<c /> world!</root>".parse().unwrap();
|
||||
///
|
||||
/// let mut iter = elem.texts();
|
||||
/// assert_eq!(iter.next().unwrap(), "hello");
|
||||
/// assert_eq!(iter.next().unwrap(), " world!");
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
#[inline] pub fn texts<'a>(&'a self) -> Texts<'a> {
|
||||
Texts {
|
||||
iter: self.children.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over mutable references to every text node of this element.
|
||||
#[inline] pub fn texts_mut<'a>(&'a mut self) -> TextsMut<'a> {
|
||||
TextsMut {
|
||||
iter: self.children.iter_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,7 +437,7 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let mut elem = Element::bare("root");
|
||||
|
@ -356,11 +470,21 @@ impl Element {
|
|||
}
|
||||
}
|
||||
|
||||
fn propagate_namespaces(&mut self) {
|
||||
let ns = self.namespace.clone();
|
||||
for child in self.children_mut() {
|
||||
if child.namespace.is_none() {
|
||||
child.namespace = ns.clone();
|
||||
child.propagate_namespaces();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Appends a text node to an `Element`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let mut elem = Element::bare("node");
|
||||
|
@ -379,7 +503,7 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::{Element, Node};
|
||||
///
|
||||
/// let mut elem = Element::bare("node");
|
||||
|
@ -396,21 +520,15 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elem: Element = "<node>hello, world!</node>".parse().unwrap();
|
||||
/// let elem: Element = "<node>hello,<split /> world!</node>".parse().unwrap();
|
||||
///
|
||||
/// assert_eq!(elem.text(), "hello, world!");
|
||||
/// ```
|
||||
pub fn text(&self) -> String {
|
||||
let mut ret = String::new();
|
||||
for fork in &self.children {
|
||||
if let Node::Text(ref s) = *fork {
|
||||
ret += s;
|
||||
}
|
||||
}
|
||||
ret
|
||||
self.texts().fold(String::new(), |ret, new| ret + new)
|
||||
}
|
||||
|
||||
/// Returns a reference to the first child element with the specific name and namespace, if it
|
||||
|
@ -418,7 +536,7 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
|
||||
|
@ -459,7 +577,7 @@ impl Element {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
|
||||
|
@ -476,7 +594,7 @@ impl Element {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over references to children of an `Element`.
|
||||
/// An iterator over references to child elements of an `Element`.
|
||||
pub struct Children<'a> {
|
||||
iter: slice::Iter<'a, Node>,
|
||||
}
|
||||
|
@ -494,7 +612,7 @@ impl<'a> Iterator for Children<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over mutable references to children of an `Element`.
|
||||
/// An iterator over mutable references to child elements of an `Element`.
|
||||
pub struct ChildrenMut<'a> {
|
||||
iter: slice::IterMut<'a, Node>,
|
||||
}
|
||||
|
@ -512,6 +630,74 @@ impl<'a> Iterator for ChildrenMut<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over references to child text nodes of an `Element`.
|
||||
pub struct Texts<'a> {
|
||||
iter: slice::Iter<'a, Node>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Texts<'a> {
|
||||
type Item = &'a str;
|
||||
|
||||
fn next(&mut self) -> Option<&'a str> {
|
||||
while let Some(item) = self.iter.next() {
|
||||
if let Node::Text(ref child) = *item {
|
||||
return Some(child);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over mutable references to child text nodes of an `Element`.
|
||||
pub struct TextsMut<'a> {
|
||||
iter: slice::IterMut<'a, Node>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for TextsMut<'a> {
|
||||
type Item = &'a mut String;
|
||||
|
||||
fn next(&mut self) -> Option<&'a mut String> {
|
||||
while let Some(item) = self.iter.next() {
|
||||
if let Node::Text(ref mut child) = *item {
|
||||
return Some(child);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over references to all child nodes of an `Element`.
|
||||
pub type Nodes<'a> = slice::Iter<'a, Node>;
|
||||
|
||||
/// An iterator over mutable references to all child nodes of an `Element`.
|
||||
pub type NodesMut<'a> = slice::IterMut<'a, Node>;
|
||||
|
||||
/// An iterator over the attributes of an `Element`.
|
||||
pub struct Attrs<'a> {
|
||||
iter: btree_map::Iter<'a, String, String>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Attrs<'a> {
|
||||
type Item = (&'a str, &'a str);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|(x, y)| (x.as_ref(), y.as_ref()))
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the attributes of an `Element`, with the values mutable.
|
||||
pub struct AttrsMut<'a> {
|
||||
iter: btree_map::IterMut<'a, String, String>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AttrsMut<'a> {
|
||||
type Item = (&'a str, &'a mut String);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next().map(|(x, y)| (x.as_ref(), y))
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder for `Element`s.
|
||||
pub struct ElementBuilder {
|
||||
root: Element,
|
||||
|
|
Loading…
Reference in a new issue