xml_data/parser/core.rs
1use crate::{
2 Result,
3 errors,
4};
5use std::borrow::Cow;
6
7/// A state to parse exactly one element
8///
9/// The idea is that a parser will try different implementors of this to parse an element it finds;
10/// the first implementor returning `Some(..)` on `parse_element_start` will be used to actually
11/// parse it.
12///
13/// After a successful `parse_element_start` the parser needs to call `parse_element_attribute` for
14/// all attributes on the element, then `parse_element_inner_text` and `parse_element_inner_node`
15/// until the closing tag of the element is hit, upon which it needs to call `parse_element_finish`.
16pub trait ElementState: Sized {
17 /// Once fully parsed this is the resulting output type.
18 type Output: Sized;
19
20 /// Try creating state to parse an element with the passed `tag`.
21 fn parse_element_start(tag: &str) -> Option<Self>;
22
23 /// Parse attribute into state
24 ///
25 /// The default implementation will fail with "unexpected attribute".
26 fn parse_element_attribute(&mut self, key: &str, value: Cow<'_, str>) -> Result<()> {
27 let _ = value;
28 return Err(errors::unexpected_attribute(key));
29 }
30
31 /// Parse text or CDATA into state.
32 ///
33 /// The default implementation will ignore whitespace and fail otherwise.
34 fn parse_element_inner_text(&mut self, text: Cow<'_, str>) -> Result<()> {
35 if !text.trim().is_empty() {
36 return Err(errors::unexpected_text());
37 }
38 Ok(())
39 }
40
41 /// Parse inner elements.
42 ///
43 /// The default implementation will fail with "unexpected element".
44 fn parse_element_inner_node<P: ElementParser>(&mut self, tag: &str, parser: P) -> Result<()> {
45 let _ = parser;
46 return Err(errors::unexpected_element(tag));
47 }
48
49 /// Finish parsing an element.
50 ///
51 /// This is where you make sure you got all required data (unpacking their types) and can
52 /// optionally check data for consistency.
53 fn parse_element_finish(self) -> Result<Self::Output>;
54
55 /// In case `parse_element_start` didn't get to accept any element (either because it always
56 /// returned `None` or there just wasn't enough data), a parser can use this to generate an
57 /// error.
58 ///
59 /// `ParseElementOnce` uses this.
60 fn parse_error_not_found<T>() -> Result<T> {
61 Err(errors::missing_unknown_element())
62 }
63}
64
65/// A parser that is ready to parse exactly one element (and nested data).
66pub trait ElementParser: Sized {
67 /// Start parsing an element with the prepared state
68 ///
69 /// A parser will call the various `ElementState` to parse the element.
70 ///
71 /// Users of this method will create the state using `ElementState::parse_element_start` and
72 /// produce the final result using `ElementState::parse_element_finish` after calling this
73 /// method.
74 fn parse_element_state<E: ElementState>(self, state: &mut E) -> Result<()>;
75}