Get rid of IntoElements
, replace it with Into<Node>
and <T: Into<Node> IntoIterator<Item = T>
. This is a backwards-incompatible change, but should require minimal changes.
Doing this splits the `append` method in `ElementBuilder` into two methods. `append` now appends exactly one node, while `append_all` appends an iterator of nodes. Add `remove_child`, which removes the first child that has a specific name and namespace, then returns it if it exists. Add a lot of convenience methods on `Node`: `as_text_mut`, `as_element_mut`, `into_text`, `into_element`.
This commit is contained in:
parent
da7de97dce
commit
c5c8dee20a
3 changed files with 162 additions and 90 deletions
|
@ -2,85 +2,6 @@
|
|||
|
||||
use element::{Element, ElementBuilder};
|
||||
|
||||
/// A struct which is used for emitting `Element`s and text nodes into an `Element` without
|
||||
/// exposing more functionality than necessary.
|
||||
pub struct ElementEmitter<'a>(&'a mut Element);
|
||||
|
||||
impl<'a> ElementEmitter<'a> {
|
||||
/// Creates a new `ElementEmitter`.
|
||||
pub fn new(root: &'a mut Element) -> ElementEmitter<'a> {
|
||||
ElementEmitter(root)
|
||||
}
|
||||
|
||||
/// Appends an `Element` to the target.
|
||||
pub fn append_child(&mut self, element: Element) {
|
||||
self.0.append_child(element);
|
||||
}
|
||||
|
||||
/// Appends a text node to the target.
|
||||
pub fn append_text_node(&mut self, text: String) {
|
||||
self.0.append_text_node(text);
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types which can be converted to one or multiple `Element`s.
|
||||
pub trait IntoElements {
|
||||
/// Emits this as a sequence of text nodes and `Element`s.
|
||||
fn into_elements(self, emitter: &mut ElementEmitter);
|
||||
}
|
||||
|
||||
impl<T: IntoElements> IntoElements for Vec<T> {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
for elem in self {
|
||||
elem.into_elements(emitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: IntoElements + Clone> IntoElements for &'a [T] {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
self.to_vec().into_elements(emitter);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IntoElements> IntoElements for Option<T> {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
if let Some(e) = self {
|
||||
e.into_elements(emitter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoElements for T where T: Into<Element> {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
emitter.append_child(self.into());
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoElements for ElementBuilder {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
emitter.append_child(self.build());
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoElements for String {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
emitter.append_text_node(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoElements for &'a String {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
emitter.append_text_node(self.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoElements for &'a str {
|
||||
fn into_elements(self, emitter: &mut ElementEmitter) {
|
||||
emitter.append_text_node(self.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for types which can be converted to an attribute value.
|
||||
pub trait IntoAttributeValue {
|
||||
/// Turns this into an attribute string, or None if it shouldn't be added.
|
||||
|
|
171
src/element.rs
171
src/element.rs
|
@ -19,7 +19,7 @@ use std::str::FromStr;
|
|||
|
||||
use std::slice;
|
||||
|
||||
use convert::{IntoElements, IntoAttributeValue, ElementEmitter};
|
||||
use convert::IntoAttributeValue;
|
||||
use namespace_set::NamespaceSet;
|
||||
|
||||
/// helper function to escape a `&[u8]` and replace all
|
||||
|
@ -80,7 +80,8 @@ pub enum Node {
|
|||
}
|
||||
|
||||
impl Node {
|
||||
/// Turns this into an `Element` if possible, else returns None.
|
||||
/// Turns this into a reference to an `Element` if this is an element node.
|
||||
/// Else this returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -101,7 +102,52 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
/// Turns this into a `String` if possible, else returns None.
|
||||
/// Turns this into a mutable reference of an `Element` if this is an element node.
|
||||
/// Else this returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Node;
|
||||
///
|
||||
/// let mut elm = Node::Element("<meow />".parse().unwrap());
|
||||
/// let mut txt = Node::Text("meow".to_owned());
|
||||
///
|
||||
/// assert_eq!(elm.as_element_mut().unwrap().name(), "meow");
|
||||
/// assert_eq!(txt.as_element_mut(), None);
|
||||
/// ```
|
||||
pub fn as_element_mut(&mut self) -> Option<&mut Element> {
|
||||
match *self {
|
||||
Node::Element(ref mut e) => Some(e),
|
||||
Node::Text(_) => None,
|
||||
Node::Comment(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns this into an `Element`, consuming self, if this is an element node.
|
||||
/// Else this returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Node;
|
||||
///
|
||||
/// let elm = Node::Element("<meow />".parse().unwrap());
|
||||
/// let txt = Node::Text("meow".to_owned());
|
||||
///
|
||||
/// assert_eq!(elm.into_element().unwrap().name(), "meow");
|
||||
/// assert_eq!(txt.into_element(), None);
|
||||
/// ```
|
||||
pub fn into_element(self) -> Option<Element> {
|
||||
match self {
|
||||
Node::Element(e) => Some(e),
|
||||
Node::Text(_) => None,
|
||||
Node::Comment(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns this into an `&str` if this is a text node.
|
||||
/// Else this returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -122,6 +168,56 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
/// Turns this into an `&mut String` if this is a text node.
|
||||
/// Else this returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Node;
|
||||
///
|
||||
/// let mut elm = Node::Element("<meow />".parse().unwrap());
|
||||
/// let mut txt = Node::Text("meow".to_owned());
|
||||
///
|
||||
/// assert_eq!(elm.as_text_mut(), None);
|
||||
/// {
|
||||
/// let text_mut = txt.as_text_mut().unwrap();
|
||||
/// assert_eq!(text_mut, "meow");
|
||||
/// text_mut.push_str("zies");
|
||||
/// assert_eq!(text_mut, "meowzies");
|
||||
/// }
|
||||
/// assert_eq!(txt.as_text().unwrap(), "meowzies");
|
||||
/// ```
|
||||
pub fn as_text_mut(&mut self) -> Option<&mut String> {
|
||||
match *self {
|
||||
Node::Element(_) => None,
|
||||
Node::Text(ref mut s) => Some(s),
|
||||
Node::Comment(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns this into an `String`, consuming self, if this is a text node.
|
||||
/// Else this returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Node;
|
||||
///
|
||||
/// let elm = Node::Element("<meow />".parse().unwrap());
|
||||
/// let txt = Node::Text("meow".to_owned());
|
||||
///
|
||||
/// assert_eq!(elm.into_text(), None);
|
||||
/// assert_eq!(txt.into_text().unwrap(), "meow");
|
||||
/// ```
|
||||
pub fn into_text(self) -> Option<String> {
|
||||
match self {
|
||||
Node::Element(_) => None,
|
||||
Node::Text(s) => Some(s),
|
||||
Node::Comment(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_to_inner<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<()>{
|
||||
match *self {
|
||||
Node::Element(ref elmt) => elmt.write_to_inner(writer)?,
|
||||
|
@ -139,6 +235,30 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Element> for Node {
|
||||
fn from(elm: Element) -> Node {
|
||||
Node::Element(elm)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Node {
|
||||
fn from(s: String) -> Node {
|
||||
Node::Text(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Node {
|
||||
fn from(s: &'a str) -> Node {
|
||||
Node::Text(s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ElementBuilder> for Node {
|
||||
fn from(builder: ElementBuilder) -> Node {
|
||||
Node::Element(builder.build())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
/// A struct representing a DOM Element.
|
||||
pub struct Element {
|
||||
|
@ -157,7 +277,6 @@ impl<'a> From<&'a Element> for String {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl FromStr for Element {
|
||||
type Err = Error;
|
||||
|
||||
|
@ -736,6 +855,34 @@ impl Element {
|
|||
pub fn has_child<N: AsRef<str>, NS: AsRef<str>>(&self, name: N, namespace: NS) -> bool {
|
||||
self.get_child(name, namespace).is_some()
|
||||
}
|
||||
|
||||
/// Removes the first child with this name and namespace, if it exists, and returns an
|
||||
/// `Option<Element>` containing this child if it succeeds.
|
||||
/// Returns `None` if no child matches this name and namespace.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use minidom::Element;
|
||||
///
|
||||
/// let mut elem: Element = r#"<node xmlns="ns"><a /><a xmlns="other_ns" /><b /></node>"#.parse().unwrap();
|
||||
///
|
||||
/// assert!(elem.remove_child("a", "ns").unwrap().is("a", "ns"));
|
||||
/// assert!(elem.remove_child("a", "ns").is_none());
|
||||
/// assert!(elem.remove_child("inexistent", "inexistent").is_none());
|
||||
/// ```
|
||||
pub fn remove_child<N: AsRef<str>, NS: AsRef<str>>(&mut self, name: N, namespace: NS) -> Option<Element> {
|
||||
let name = name.as_ref();
|
||||
let namespace = namespace.as_ref();
|
||||
let idx = self.children.iter().position(|x| {
|
||||
if let Node::Element(ref elm) = x {
|
||||
elm.is(name, namespace)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})?;
|
||||
self.children.remove(idx).into_element()
|
||||
}
|
||||
}
|
||||
|
||||
fn split_element_name<S: AsRef<str>>(s: S) -> Result<(Option<String>, String)> {
|
||||
|
@ -900,11 +1047,16 @@ impl ElementBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Appends anything implementing `IntoElements` into the tree.
|
||||
pub fn append<T: IntoElements>(mut self, into: T) -> ElementBuilder {
|
||||
{
|
||||
let mut emitter = ElementEmitter::new(&mut self.root);
|
||||
into.into_elements(&mut emitter);
|
||||
/// Appends anything implementing `Into<Node>` into the tree.
|
||||
pub fn append<T: Into<Node>>(mut self, node: T) -> ElementBuilder {
|
||||
self.root.append_node(node.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Appends an iterator of things implementing `Into<Node>` into the tree.
|
||||
pub fn append_all<T: Into<Node>, I: IntoIterator<Item = T>>(mut self, iter: I) -> ElementBuilder {
|
||||
for node in iter {
|
||||
self.root.append_node(node.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -920,7 +1072,6 @@ impl ElementBuilder {
|
|||
e.namespaces.set_parent(Rc::clone(&element.namespaces));
|
||||
}
|
||||
}
|
||||
|
||||
element
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,4 +77,4 @@ mod namespace_set;
|
|||
|
||||
pub use error::{Error, Result};
|
||||
pub use element::{Element, Node, Children, ChildrenMut, ElementBuilder};
|
||||
pub use convert::{IntoElements, IntoAttributeValue, ElementEmitter};
|
||||
pub use convert::IntoAttributeValue;
|
||||
|
|
Loading…
Reference in a new issue