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