node.rs

  1// Copyright (c) 2020 lumi <lumi@pew.im>
  2// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  3// Copyright (c) 2020 Maxime “pep” Buquet <pep@bouah.net>
  4//
  5// This Source Code Form is subject to the terms of the Mozilla Public
  6// License, v. 2.0. If a copy of the MPL was not distributed with this
  7// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  8
  9//! Provides the `Node` struct, which represents a node in the DOM.
 10
 11use crate::element::{Element, ElementBuilder};
 12use crate::error::Result;
 13
 14use std::io::Write;
 15
 16use quick_xml::events::{BytesText, Event};
 17use quick_xml::Writer as EventWriter;
 18
 19/// A node in an element tree.
 20#[derive(Clone, Debug, Eq)]
 21pub enum Node {
 22    /// An `Element`.
 23    Element(Element),
 24    /// A text node.
 25    Text(String),
 26    #[cfg(feature = "comments")]
 27    /// A comment node.
 28    Comment(String),
 29}
 30
 31impl Node {
 32    /// Turns this into a reference to an `Element` if this is an element node.
 33    /// Else this returns `None`.
 34    ///
 35    /// # Examples
 36    ///
 37    /// ```rust
 38    /// use minidom::Node;
 39    ///
 40    /// let elm = Node::Element("<meow />".parse().unwrap());
 41    /// let txt = Node::Text("meow".to_owned());
 42    ///
 43    /// assert_eq!(elm.as_element().unwrap().name(), "meow");
 44    /// assert_eq!(txt.as_element(), None);
 45    /// ```
 46    pub fn as_element(&self) -> Option<&Element> {
 47        match *self {
 48            Node::Element(ref e) => Some(e),
 49            Node::Text(_) => None,
 50            #[cfg(feature = "comments")]
 51            Node::Comment(_) => None,
 52        }
 53    }
 54
 55    /// Turns this into a mutable reference of an `Element` if this is an element node.
 56    /// Else this returns `None`.
 57    ///
 58    /// # Examples
 59    ///
 60    /// ```rust
 61    /// use minidom::Node;
 62    ///
 63    /// let mut elm = Node::Element("<meow />".parse().unwrap());
 64    /// let mut txt = Node::Text("meow".to_owned());
 65    ///
 66    /// assert_eq!(elm.as_element_mut().unwrap().name(), "meow");
 67    /// assert_eq!(txt.as_element_mut(), None);
 68    /// ```
 69    pub fn as_element_mut(&mut self) -> Option<&mut Element> {
 70        match *self {
 71            Node::Element(ref mut e) => Some(e),
 72            Node::Text(_) => None,
 73            #[cfg(feature = "comments")]
 74            Node::Comment(_) => None,
 75        }
 76    }
 77
 78    /// Turns this into an `Element`, consuming self, if this is an element node.
 79    /// Else this returns `None`.
 80    ///
 81    /// # Examples
 82    ///
 83    /// ```rust
 84    /// use minidom::Node;
 85    ///
 86    /// let elm = Node::Element("<meow />".parse().unwrap());
 87    /// let txt = Node::Text("meow".to_owned());
 88    ///
 89    /// assert_eq!(elm.into_element().unwrap().name(), "meow");
 90    /// assert_eq!(txt.into_element(), None);
 91    /// ```
 92    pub fn into_element(self) -> Option<Element> {
 93        match self {
 94            Node::Element(e) => Some(e),
 95            Node::Text(_) => None,
 96            #[cfg(feature = "comments")]
 97            Node::Comment(_) => None,
 98        }
 99    }
100
101    /// Turns this into an `&str` if this is a text node.
102    /// Else this returns `None`.
103    ///
104    /// # Examples
105    ///
106    /// ```rust
107    /// use minidom::Node;
108    ///
109    /// let elm = Node::Element("<meow />".parse().unwrap());
110    /// let txt = Node::Text("meow".to_owned());
111    ///
112    /// assert_eq!(elm.as_text(), None);
113    /// assert_eq!(txt.as_text().unwrap(), "meow");
114    /// ```
115    pub fn as_text(&self) -> Option<&str> {
116        match *self {
117            Node::Element(_) => None,
118            Node::Text(ref s) => Some(s),
119            #[cfg(feature = "comments")]
120            Node::Comment(_) => None,
121        }
122    }
123
124    /// Turns this into an `&mut String` if this is a text node.
125    /// Else this returns `None`.
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use minidom::Node;
131    ///
132    /// let mut elm = Node::Element("<meow />".parse().unwrap());
133    /// let mut txt = Node::Text("meow".to_owned());
134    ///
135    /// assert_eq!(elm.as_text_mut(), None);
136    /// {
137    ///     let text_mut = txt.as_text_mut().unwrap();
138    ///     assert_eq!(text_mut, "meow");
139    ///     text_mut.push_str("zies");
140    ///     assert_eq!(text_mut, "meowzies");
141    /// }
142    /// assert_eq!(txt.as_text().unwrap(), "meowzies");
143    /// ```
144    pub fn as_text_mut(&mut self) -> Option<&mut String> {
145        match *self {
146            Node::Element(_) => None,
147            Node::Text(ref mut s) => Some(s),
148            #[cfg(feature = "comments")]
149            Node::Comment(_) => None,
150        }
151    }
152
153    /// Turns this into an `String`, consuming self, if this is a text node.
154    /// Else this returns `None`.
155    ///
156    /// # Examples
157    ///
158    /// ```rust
159    /// use minidom::Node;
160    ///
161    /// let elm = Node::Element("<meow />".parse().unwrap());
162    /// let txt = Node::Text("meow".to_owned());
163    ///
164    /// assert_eq!(elm.into_text(), None);
165    /// assert_eq!(txt.into_text().unwrap(), "meow");
166    /// ```
167    pub fn into_text(self) -> Option<String> {
168        match self {
169            Node::Element(_) => None,
170            Node::Text(s) => Some(s),
171            #[cfg(feature = "comments")]
172            Node::Comment(_) => None,
173        }
174    }
175
176    #[doc(hidden)]
177    pub(crate) fn write_to_inner<W: Write>(&self, writer: &mut EventWriter<W>) -> Result<()> {
178        match *self {
179            Node::Element(ref elmt) => elmt.write_to_inner(writer)?,
180            Node::Text(ref s) => {
181                writer.write_event(Event::Text(BytesText::from_plain_str(s)))?;
182            }
183            #[cfg(feature = "comments")]
184            Node::Comment(ref s) => {
185                writer.write_event(Event::Comment(BytesText::from_plain_str(s)))?;
186            }
187        }
188
189        Ok(())
190    }
191}
192
193impl<I> From<I> for Node
194where
195    I: Into<Element>,
196{
197    fn from(elm: I) -> Node {
198        Node::Element(elm.into())
199    }
200}
201
202impl From<String> for Node {
203    fn from(s: String) -> Node {
204        Node::Text(s)
205    }
206}
207
208impl<'a> From<&'a str> for Node {
209    fn from(s: &'a str) -> Node {
210        Node::Text(s.to_owned())
211    }
212}
213
214impl From<ElementBuilder> for Node {
215    fn from(builder: ElementBuilder) -> Node {
216        Node::Element(builder.build())
217    }
218}
219
220impl PartialEq for Node {
221    fn eq(&self, other: &Self) -> bool {
222        match (self, other) {
223            (&Node::Element(ref elem1), &Node::Element(ref elem2)) => elem1 == elem2,
224            (&Node::Text(ref text1), &Node::Text(ref text2)) => text1 == text2,
225            #[cfg(feature = "comments")]
226            (&Node::Comment(ref text1), &Node::Comment(ref text2)) => text1 == text2,
227            _ => false,
228        }
229    }
230}