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};
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, PartialEq, 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::new(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}