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::collections::BTreeMap;
 15use std::io::Write;
 16
 17use quick_xml::events::{BytesText, Event};
 18use quick_xml::Writer as EventWriter;
 19
 20/// A node in an element tree.
 21#[derive(Clone, Debug, Eq)]
 22pub enum Node {
 23    /// An `Element`.
 24    Element(Element),
 25    /// A text node.
 26    Text(String),
 27}
 28
 29impl Node {
 30    /// Turns this into a reference to an `Element` if this is an element node.
 31    /// Else this returns `None`.
 32    ///
 33    /// # Examples
 34    ///
 35    /// ```rust
 36    /// use minidom::Node;
 37    ///
 38    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
 39    /// let txt = Node::Text("meow".to_owned());
 40    ///
 41    /// assert_eq!(elm.as_element().unwrap().name(), "meow");
 42    /// assert_eq!(txt.as_element(), None);
 43    /// ```
 44    pub fn as_element(&self) -> Option<&Element> {
 45        match *self {
 46            Node::Element(ref e) => Some(e),
 47            Node::Text(_) => None,
 48        }
 49    }
 50
 51    /// Turns this into a mutable reference of an `Element` if this is an element node.
 52    /// Else this returns `None`.
 53    ///
 54    /// # Examples
 55    ///
 56    /// ```rust
 57    /// use minidom::Node;
 58    ///
 59    /// let mut elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
 60    /// let mut txt = Node::Text("meow".to_owned());
 61    ///
 62    /// assert_eq!(elm.as_element_mut().unwrap().name(), "meow");
 63    /// assert_eq!(txt.as_element_mut(), None);
 64    /// ```
 65    pub fn as_element_mut(&mut self) -> Option<&mut Element> {
 66        match *self {
 67            Node::Element(ref mut e) => Some(e),
 68            Node::Text(_) => None,
 69        }
 70    }
 71
 72    /// Turns this into an `Element`, consuming self, if this is an element node.
 73    /// Else this returns `None`.
 74    ///
 75    /// # Examples
 76    ///
 77    /// ```rust
 78    /// use minidom::Node;
 79    ///
 80    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
 81    /// let txt = Node::Text("meow".to_owned());
 82    ///
 83    /// assert_eq!(elm.into_element().unwrap().name(), "meow");
 84    /// assert_eq!(txt.into_element(), None);
 85    /// ```
 86    pub fn into_element(self) -> Option<Element> {
 87        match self {
 88            Node::Element(e) => Some(e),
 89            Node::Text(_) => None,
 90        }
 91    }
 92
 93    /// Turns this into an `&str` if this is a text node.
 94    /// Else this returns `None`.
 95    ///
 96    /// # Examples
 97    ///
 98    /// ```rust
 99    /// use minidom::Node;
100    ///
101    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
102    /// let txt = Node::Text("meow".to_owned());
103    ///
104    /// assert_eq!(elm.as_text(), None);
105    /// assert_eq!(txt.as_text().unwrap(), "meow");
106    /// ```
107    pub fn as_text(&self) -> Option<&str> {
108        match *self {
109            Node::Element(_) => None,
110            Node::Text(ref s) => Some(s),
111        }
112    }
113
114    /// Turns this into an `&mut String` if this is a text node.
115    /// Else this returns `None`.
116    ///
117    /// # Examples
118    ///
119    /// ```rust
120    /// use minidom::Node;
121    ///
122    /// let mut elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
123    /// let mut txt = Node::Text("meow".to_owned());
124    ///
125    /// assert_eq!(elm.as_text_mut(), None);
126    /// {
127    ///     let text_mut = txt.as_text_mut().unwrap();
128    ///     assert_eq!(text_mut, "meow");
129    ///     text_mut.push_str("zies");
130    ///     assert_eq!(text_mut, "meowzies");
131    /// }
132    /// assert_eq!(txt.as_text().unwrap(), "meowzies");
133    /// ```
134    pub fn as_text_mut(&mut self) -> Option<&mut String> {
135        match *self {
136            Node::Element(_) => None,
137            Node::Text(ref mut s) => Some(s),
138        }
139    }
140
141    /// Turns this into an `String`, consuming self, if this is a text node.
142    /// Else this returns `None`.
143    ///
144    /// # Examples
145    ///
146    /// ```rust
147    /// use minidom::Node;
148    ///
149    /// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
150    /// let txt = Node::Text("meow".to_owned());
151    ///
152    /// assert_eq!(elm.into_text(), None);
153    /// assert_eq!(txt.into_text().unwrap(), "meow");
154    /// ```
155    pub fn into_text(self) -> Option<String> {
156        match self {
157            Node::Element(_) => None,
158            Node::Text(s) => Some(s),
159        }
160    }
161
162    #[doc(hidden)]
163    pub(crate) fn write_to_inner<W: Write>(
164        &self,
165        writer: &mut EventWriter<W>,
166        prefixes: &mut BTreeMap<Option<String>, String>,
167    ) -> Result<()> {
168        match *self {
169            Node::Element(ref elmt) => elmt.write_to_inner(writer, prefixes)?,
170            Node::Text(ref s) => {
171                writer.write_event(Event::Text(BytesText::from_plain_str(s)))?;
172            }
173        }
174
175        Ok(())
176    }
177}
178
179impl<I> From<I> for Node
180where
181    I: Into<Element>,
182{
183    fn from(elm: I) -> Node {
184        Node::Element(elm.into())
185    }
186}
187
188impl From<String> for Node {
189    fn from(s: String) -> Node {
190        Node::Text(s)
191    }
192}
193
194impl<'a> From<&'a str> for Node {
195    fn from(s: &'a str) -> Node {
196        Node::Text(s.to_owned())
197    }
198}
199
200impl From<ElementBuilder> for Node {
201    fn from(builder: ElementBuilder) -> Node {
202        Node::Element(builder.build())
203    }
204}
205
206impl PartialEq for Node {
207    fn eq(&self, other: &Self) -> bool {
208        match (self, other) {
209            (&Node::Element(ref elem1), &Node::Element(ref elem2)) => elem1 == elem2,
210            (&Node::Text(ref text1), &Node::Text(ref text2)) => text1 == text2,
211            _ => false,
212        }
213    }
214}