Skip to main content

parco_xml/dexml/
tag_end.rs

1use std::borrow::Cow;
2
3use crate::{
4    DeXmlError,
5    de::Reader,
6    dexml::{
7        lex::{CloseAngle, Slash},
8        parse::Action,
9    },
10};
11
12/// the ending tag of an element i.e "\>" in "\<Element\>"
13#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum TagEnd {
15    /// A self closing tag ending with \/\>. No children
16    SelfClosing,
17    /// A normal closing tag \>. Potential children
18    Normal,
19}
20
21impl<'a> Reader<'a> {
22    /// parse the ending of a tag, if there are attributes it will consume them and then the end of the element
23    pub fn tag_end(&mut self) -> Result<TagEnd, DeXmlError> {
24        loop {
25            if self.lexer.peek('/') {
26                self.parse::<Slash>(Action::TagEnd)?;
27                self.parse::<CloseAngle>(Action::TagEnd)?;
28                return Ok(TagEnd::SelfClosing);
29            }
30            if self.lexer.peek('>') {
31                self.parse::<CloseAngle>(Action::TagEnd)?;
32                return Ok(TagEnd::Normal);
33            }
34            self.attr()?;
35        }
36    }
37
38    /// assert this element IS NOT a [`TagEnd::SelfClosing`]
39    pub fn assert_children(&mut self) -> Result<(), DeXmlError> {
40        match self.tag_end()? {
41            TagEnd::Normal => Ok(()),
42            TagEnd::SelfClosing => Err(self.err(Cow::Borrowed(DeXmlError::EXPECTED_CHILDREN))),
43        }
44    }
45
46    /// if the element has a [`TagEnd::SelfClosing`] does nothing
47    /// if the element has a [`TagEnd::Normal`] attempts to parse the closing "\<\/Element\>"
48    ///
49    /// some elements end in self closing tags such as: "\<Element \/\>"
50    /// while others look like: "\<Element\>\<\/Element\>"
51    /// [`Reader::tag_close_infer`] can be used in combination with the output of [`Reader::tag_end`]
52    /// to parse these correctly
53    ///
54    /// e.x:
55    ///
56    /// ```rust,ignore
57    /// let tag_end = reader.tag_end()?;
58    /// // if the element was self closing it does nothing, else parse the closing tag
59    /// reader.tag_close_infer(tag_end)?;
60    /// ```
61    pub fn tag_close_infer(&mut self, tag_end: TagEnd) -> Result<(), DeXmlError> {
62        match tag_end {
63            TagEnd::SelfClosing => Ok(()),
64            TagEnd::Normal => self.close_tag(),
65        }
66    }
67}