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}