tree_xml/
node.rs

1use core::{fmt, str};
2use std::borrow::Cow;
3use std::collections::{HashMap, VecDeque};
4use std::io::{BufRead, Cursor, Write};
5use std::str::FromStr;
6
7#[cfg(feature = "log")]
8use log::{error, info, trace, warn};
9use quick_xml::events::attributes::Attribute;
10use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
11use quick_xml::name::QName;
12use quick_xml::{Reader, Writer};
13
14use crate::error::Error;
15use crate::error::ParseNodeError;
16use crate::error::Result;
17
18/// A high level tree representation of an XML DOM class.
19#[derive(Debug, Default, Clone, PartialEq, Eq)]
20pub struct Node {
21    name: String,
22    content: String,
23    attributes: HashMap<String, String>,
24    childs: Vec<Node>,
25}
26
27/// A builder for a [`Node`] struct.
28#[derive(Debug, Default, Clone)]
29pub struct NodeBuilder<'a> {
30    name: &'a str,
31    content: &'a str,
32    attributes: HashMap<String, String>,
33    childs: Vec<Node>,
34}
35
36impl Node {
37    /// Gets a [`NodeBuilder`] for a [`Node`] with a specified name.
38    #[must_use]
39    pub fn builder(name: &str) -> NodeBuilder {
40        #[cfg(feature = "log")]
41        trace!("new builder for {}", name);
42        NodeBuilder::new(name)
43    }
44
45    /// Gets the name of the current [`Node`].
46    #[must_use]
47    pub fn name(&self) -> &str {
48        self.name.as_str()
49    }
50
51    /// Gets the content of the current [`Node`].
52    #[must_use]
53    pub fn content(&self) -> &str {
54        self.content.as_str()
55    }
56
57    /// Searches for a attribute with the specified key and return it if it is found return it as a [`prim@str`].
58    ///
59    /// # Errors
60    ///
61    /// This function will return an error if the [`Node`] has no attribute with the given key.
62    pub fn attribute(&self, key: &str) -> Result<&str> {
63        #[cfg(feature = "log")]
64        trace!("searching for attribute '{}' in <{}>", key, self.name());
65        self.attributes
66            .get(key)
67            .map(std::string::String::as_str)
68            .ok_or_else(|| {
69                ParseNodeError::MissingAttribute(key.to_owned(), self.name.clone()).into()
70            })
71    }
72
73    /// Gets the childs of the [`Node`] as an [`Iterator`].
74    pub fn childs(&self) -> impl Iterator<Item = &Self> {
75        self.childs.iter()
76    }
77
78    /// Checks if the [`Node`] has an attribute with the given key.
79    #[must_use]
80    pub fn has_attribute(&self, key: &str) -> bool {
81        #[cfg(feature = "log")]
82        trace!("searching for attribute '{}' in <{}>", key, self.name());
83        self.attributes.contains_key(key)
84    }
85
86    /// Checks if the [`Node`] has childs.
87    #[must_use]
88    pub fn has_childs(&self) -> bool {
89        !self.childs.is_empty()
90    }
91
92    /// Gets the amount of childs the [`Node`] has.
93    #[must_use]
94    pub fn child_count(&self) -> usize {
95        self.childs.len()
96    }
97
98    /// Searches for a child with the given name.
99    ///
100    /// # Errors
101    ///
102    /// This function will return an error if the [`Node`] has no child with the given name.
103    pub fn child_by_name<'a, 'n: 'a>(&'a self, name: &'n str) -> Result<&'a Self> {
104        #[cfg(feature = "log")]
105        trace!("searching for child <{}> inside of <{}>", name, self.name());
106        self.childs_by_name(name)
107            .next()
108            .ok_or_else(|| ParseNodeError::MissingChild(name.to_owned(), self.name.clone()).into())
109    }
110
111    /// Returns an iterator with all childs that have the given name.
112    pub fn childs_by_name<'a, 'n: 'a>(
113        &'a self,
114        name: &'n str,
115    ) -> impl Iterator<Item = &'a Self> + 'a {
116        #[cfg(feature = "log")]
117        trace!(
118            "construct iterator from all childs <{}> from parent <{}>",
119            name,
120            self.name()
121        );
122        self.childs.iter().filter(move |c| c.name == name)
123    }
124
125    /// Write the XML [`Node`] as a character stream to the given [`Writer`]. Internal function only.
126    ///
127    /// # Errors
128    ///
129    /// This function will return an error if the event writing on the [`Writer`] fails.
130    fn write_to_impl<W>(&self, writer: &mut Writer<W>) -> Result<()>
131    where
132        W: std::io::Write,
133    {
134        let start = BytesStart::from(self);
135
136        if self.childs.is_empty() && self.content.is_empty() {
137            writer.write_event(Event::Empty(start))?;
138        } else {
139            writer.write_event(Event::Start(start))?;
140
141            if !self.content.is_empty() {
142                writer.write_event(Event::Text(BytesText::new(&self.content)))?;
143            }
144
145            if !self.childs.is_empty() {
146                for child in &self.childs {
147                    child.write_to(writer)?;
148                }
149            }
150
151            writer.write_event(Event::End(BytesEnd::new(&self.name)))?;
152        }
153
154        Ok(())
155    }
156
157    /// Write the XML [`Node`] as a character stream to the given [`Writer`].
158    ///
159    /// # Errors
160    ///
161    /// This function will return an error if the event writing on the [`Writer`] fails.
162    pub fn write_to<W>(&self, writer: &mut Writer<W>) -> Result<()>
163    where
164        W: Write,
165    {
166        #[cfg(feature = "log")]
167        trace!("writing <{}>", self.name());
168        self.write_to_impl(writer)?;
169        writer.get_mut().flush()?;
170
171        Ok(())
172    }
173
174    /// Parses the stream from a [`Reader`] to a [`Node`]
175    ///
176    /// # Errors
177    ///
178    /// This function will return an error if the [`Reader`] gets an errous value or if the end of the stream is reached.
179    pub fn read_from<R>(reader: &mut Reader<R>) -> Result<Self>
180    where
181        R: BufRead,
182    {
183        let mut node_stack = VecDeque::<Self>::new();
184        let mut buf = Vec::new();
185
186        let node = loop {
187            match reader.read_event_into(&mut buf) {
188                Ok(Event::Start(ref start)) => {
189                    #[cfg(feature = "log")]
190                    trace!("Read start event");
191                    let node = Self::try_from(start)?;
192                    node_stack.push_back(node);
193                }
194                Ok(Event::Empty(ref start)) => {
195                    #[cfg(feature = "log")]
196                    trace!("Read empty event");
197                    let node = Self::try_from(start)?;
198                    if let Some(mut parent) = node_stack.pop_back() {
199                        parent.childs.push(node);
200                        node_stack.push_back(parent);
201                    } else {
202                        break Ok(node);
203                    }
204                }
205                Ok(Event::End(ref end)) => {
206                    #[cfg(feature = "log")]
207                    trace!("Read end event");
208                    #[cfg(not(feature = "log"))]
209                    let _ = end;
210                    if let Some(node) = node_stack.pop_back() {
211                        if let Some(mut parent) = node_stack.pop_back() {
212                            parent.childs.push(node);
213                            node_stack.push_back(parent);
214                        } else {
215                            break Ok(node);
216                        }
217                    } else {
218                        #[cfg(feature = "log")]
219                        error!(
220                            "Found closing element </{}> without an opening element before",
221                            str::from_utf8(end.name().as_ref())?
222                        );
223                    }
224                }
225                Ok(Event::Text(ref t)) => {
226                    #[cfg(feature = "log")]
227                    trace!("Read text event");
228                    let content = str::from_utf8(t)?.trim();
229                    if !content.is_empty() {
230                        if let Some(node) = node_stack.back_mut() {
231                            node.content += content;
232                        } else {
233                            #[cfg(feature = "log")]
234                            warn!("Found characters {} outside of any node", content);
235                        }
236                    }
237                }
238                Ok(Event::Eof) => break Err(Error::Eof),
239                Err(e) => break Err(Error::from(e)),
240                #[cfg(feature = "log")]
241                ev => info!("Read other event: {:?}", ev),
242                #[cfg(not(feature = "log"))]
243                _ => {}
244            }
245        }?;
246
247        Ok(node)
248    }
249}
250
251impl<'a> TryFrom<&BytesStart<'a>> for Node {
252    type Error = Error;
253
254    fn try_from(value: &BytesStart<'a>) -> Result<Self> {
255        Ok(Self {
256            name: str::from_utf8(value.name().as_ref())?.to_owned(),
257            content: String::new(),
258            attributes: value
259                .attributes()
260                .map(|res| {
261                    let attribute = res?;
262                    let key = str::from_utf8(attribute.key.as_ref())?.to_owned();
263                    let value = str::from_utf8(&attribute.value)?.to_owned();
264                    Ok((key, value))
265                })
266                .collect::<Result<HashMap<_, _>>>()?,
267            childs: Vec::new(),
268        })
269    }
270}
271
272impl<'a> From<&'a Node> for BytesStart<'a> {
273    fn from(node: &'a Node) -> Self {
274        BytesStart::new(&node.name).with_attributes(node.attributes.iter().map(|(k, v)| {
275            Attribute {
276                key: QName(k.as_bytes()),
277                value: Cow::Borrowed(v.as_bytes()),
278            }
279        }))
280    }
281}
282
283impl fmt::Display for Node {
284    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285        let mut writer = Writer::new(Cursor::new(Vec::new()));
286        self.write_to(&mut writer).map_err(|_| fmt::Error)?;
287        write!(
288            f,
289            "{}",
290            str::from_utf8(&writer.into_inner().into_inner()).map_err(|_| fmt::Error)?
291        )
292    }
293}
294
295impl FromStr for Node {
296    type Err = Error;
297
298    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
299        Self::read_from(&mut Reader::from_str(s))
300    }
301}
302
303impl<'a> NodeBuilder<'a> {
304    /// Creates a builder for a [`Node`] with the name set to the givin parameter.
305    #[must_use]
306    pub fn new(name: &'a str) -> Self {
307        Self {
308            name,
309            content: "",
310            attributes: HashMap::new(),
311            childs: Vec::new(),
312        }
313    }
314
315    /// Sets the name of the [`NodeBuilder`].
316    #[must_use]
317    pub const fn name(mut self, name: &'a str) -> Self {
318        self.name = name;
319        self
320    }
321
322    /// Sets the content of the [`NodeBuilder`].
323    #[must_use]
324    pub const fn content(mut self, data: &'a str) -> Self {
325        self.content = data;
326        self
327    }
328
329    /// Adds all key-value pairs from an iterator to the attributes of the [`NodeBuilder`].
330    #[must_use]
331    pub fn attributes(mut self, attributes: impl IntoIterator<Item = (String, String)>) -> Self {
332        self.attributes.extend(attributes);
333        self
334    }
335
336    /// Adds an key-value pair as attributes to the [`NodeBuilder`].
337    #[must_use]
338    pub fn attribute(
339        mut self,
340        key: &(impl ToString + ?Sized),
341        value: &(impl ToString + ?Sized),
342    ) -> Self {
343        self.attributes.insert(key.to_string(), value.to_string());
344        self
345    }
346
347    /// Adds all nodes from an iterator to the [`NodeBuilder`] as childs.
348    #[must_use]
349    pub fn childs(mut self, childs: impl IntoIterator<Item = Node>) -> Self {
350        self.childs.extend(childs);
351        self
352    }
353
354    /// Adds a [`Node`] as a child to the [`Node`]
355    #[must_use]
356    pub fn child(mut self, child: impl Into<Node>) -> Self {
357        self.childs.push(child.into());
358        self
359    }
360
361    /// Adds a possible [`Node`] as a child to the [`NodeBuilder`].
362    #[must_use]
363    pub fn option_child(mut self, child: Option<impl Into<Node>>) -> Self {
364        if let Some(child) = child {
365            self.childs.push(child.into());
366        }
367        self
368    }
369
370    /// Tries to add the given struct as a child to the [`NodeBuilder`].
371    ///
372    /// # Errors
373    ///
374    /// This function will return an error if the child parameter cannot be succesfully be parsed into a node.
375    pub fn try_child(mut self, child: impl TryInto<Node, Error = Error>) -> Result<Self> {
376        self.childs.push(child.try_into()?);
377        Ok(self)
378    }
379
380    /// Builds the node.
381    #[must_use]
382    pub fn build(self) -> Node {
383        Node {
384            name: self.name.to_owned(),
385            content: self.content.to_owned(),
386            attributes: self.attributes,
387            childs: self.childs,
388        }
389    }
390}
391
392impl<'a> From<NodeBuilder<'a>> for Node {
393    fn from(builder: NodeBuilder<'a>) -> Self {
394        builder.build()
395    }
396}