parse/xml/
element.rs

1use roxmltree::{
2    Node,
3    NodeType,
4};
5use std::ops::Range;
6
7use crate::{
8    LowerName,
9    NameError,
10};
11
12use super::{
13    Once,
14    Parsed,
15    ParseError,
16    missing_attribute,
17    unexpected_attribute,
18};
19
20/// Raise a `Duplicate element` error
21pub fn duplicate_element<E>(
22    element_name: &str,
23    duplicate_range: Range<usize>,
24    existing_range: Range<usize>,
25    errors: &mut Vec<E>,
26)
27where
28    E: From<ParseError>,
29{
30    errors.push(ParseError::DuplicateElement {
31        element: element_name.to_owned(),
32        duplicate: duplicate_range.into(),
33        existing: existing_range.into(),
34    }.into());
35}
36
37/// Used when iterating over node children
38/// and you are only expecting elements.
39///
40/// For each element, return it's name
41///
42/// For all other comments, pi & text raise an error.
43///
44/// # Example:
45///
46/// ```
47/// for child in element.children() {
48///     let Some(name) = element_name(&child, errors) else {
49///         continue;
50///     };
51///
52///     match name {
53///         "..." =>
54///             do_somthing(),
55///
56///         _ =>
57///             unexpected_element(child, errors),
58///     }
59/// }
60/// ```
61pub fn element_name<'input, E>(
62    child: &Node<'input, 'input>,
63    errors: &mut Vec<E>,
64) -> Option<&'input str>
65where
66    E: From<ParseError>,
67{
68    match child.node_type() {
69        NodeType::Element =>
70            return Some(child.tag_name().name()),
71
72        NodeType::Text =>
73            if let Some(text) = child.text() {
74                if text.split_ascii_whitespace().next().is_some() {
75                    errors.push(
76                        ParseError::UnexpectedElement {
77                            unexpected: child.range().into(),
78                        }.into(),
79                    );
80                }
81            },
82
83        NodeType::Comment =>
84            (),
85
86        _ =>
87            errors.push(
88                ParseError::UnexpectedElement {
89                    unexpected: child.range().into(),
90                }.into(),
91            ),
92    }
93
94    None
95}
96
97impl<T> Once<T> {
98    /// Check if duplicate element is being parsed.
99    ///
100    /// If a duplicate is being parsed, return `true` and
101    /// raise an error.
102    ///
103    /// Otherwise, return `false`.
104    pub fn is_duplicate_element<'input, E>(
105        &self,
106        element: &Node<'input, 'input>,
107        errors: &mut Vec<E>,
108    ) -> bool
109    where
110        E: From<ParseError>,
111    {
112        match self {
113            Once::Success { name_range, .. } |
114            Once::Failure { name_range, .. } => {
115                duplicate_element(
116                    element.tag_name().name(),
117                    element.range(),
118                    name_range.clone(),
119                    errors,
120                );
121
122                true
123            }
124
125            Once::Missing { .. } =>
126                false,
127        }
128    }
129}
130
131impl Once<usize> {
132    /// Parse a single length element,
133    /// a `usize` with bounded range.
134    pub fn length_element<'input, E>(
135        &mut self,
136        attribute_name: &'static str,
137        range: std::ops::RangeInclusive<usize>,
138        element: Node<'input, 'input>,
139        errors: &mut Vec<E>,
140    )
141    where
142        E: From<ParseError>,
143    {
144        if self.is_duplicate_element(&element, errors) {
145            return;
146        }
147
148        let mut value = Once::new(attribute_name);
149
150        for attribute in element.attributes() {
151            if attribute.name() == attribute_name {
152                value.length_attribute(range.clone(), attribute, errors);
153            } else {
154                unexpected_attribute(attribute, errors);
155            }
156        }
157
158        for child in element.children() {
159            unexpected_element(child, errors);
160        }
161
162        match value {
163            Once::Success { value, .. } =>
164                self.element_success(element, value),
165
166            Once::Failure { .. } =>
167                self.element_failure(element),
168
169            Once::Missing { name } => {
170                missing_attribute(name, &element, errors);
171
172                self.element_failure(element);
173            }
174        }
175    }
176}
177
178/// Parse a single lowercase name of the form
179/// `<element attribute=''/>`
180pub fn lower_name_attribute_in_element<'input, E>(
181    attribute_name: &'static str,
182    element: &Node<'input, 'input>,
183    errors: &mut Vec<E>,
184) -> Option<Parsed<LowerName>>
185where
186    E: From<NameError> + From<ParseError>,
187{
188    let mut found = Once::new(attribute_name);
189
190    for attribute in element.attributes() {
191        if attribute.name() == attribute_name {
192            found.lower_name_attribute(attribute, errors);
193        } else {
194            unexpected_attribute(attribute, errors);
195        }
196    }
197
198    for child in element.children() {
199        unexpected_element(child, errors);
200    }
201
202    found.required_parsed_attribute(element, errors)
203}
204
205/// Raise a `Missing element` error
206pub fn missing_element<'input, E>(
207    name: &str,
208    parent: &Node<'input, 'input>,
209    errors: &mut Vec<E>,
210)
211where
212    E: From<ParseError>,
213{
214    errors.push(ParseError::MissingElement {
215        element: name.to_owned(),
216        parent: parent.range().into(),
217    }.into());
218}
219
220/// Raise a `Missing element` error
221pub fn missing_element_range<E>(
222    name: &str,
223    range: Range<usize>,
224    errors: &mut Vec<E>,
225)
226where
227    E: From<ParseError>,
228{
229    errors.push(ParseError::MissingElement {
230        element: name.to_owned(),
231        parent: range.into(),
232    }.into());
233}
234
235impl Once<String> {
236    /// Parse a string element checking for duplicates
237    pub fn string_element<'input, E>(
238        &mut self,
239        element: Node<'input, 'input>,
240        errors: &mut Vec<E>,
241    )
242    where
243        E: From<ParseError>,
244    {
245        if self.is_duplicate_element(&element, errors) {
246            return;
247        }
248
249        if let Some(value) = string_in_element(&element, errors) {
250            self.element_parsed_success(element, value);
251        } else {
252            self.element_failure(element);
253        }
254    }
255
256    /// Parse a string element checking for duplicates
257    ///
258    /// Ignore attributes
259    pub fn string_element_ignore_attributes<'input, E>(
260        &mut self,
261        element: Node<'input, 'input>,
262        errors: &mut Vec<E>,
263    )
264    where
265        E: From<ParseError>,
266    {
267        if self.is_duplicate_element(&element, errors) {
268            return;
269        }
270
271        if let Some(value) = string_in_element_ignore_attributes(&element, errors) {
272            self.element_parsed_success(element, value);
273        } else {
274            self.element_failure(element);
275        }
276    }
277}
278
279/// Parse and return a string in an element
280pub fn string_in_element<'input, E>(
281    element: &Node<'input, 'input>,
282    errors: &mut Vec<E>,
283) -> Option<Parsed<String>>
284where
285    E: From<ParseError>,
286{
287    for attribute in element.attributes() {
288        unexpected_attribute(attribute, errors);
289    }
290
291    string_in_element_ignore_attributes(element, errors)
292}
293
294/// Parse and return a string in an element
295pub fn string_in_element_ignore_attributes<'input, E>(
296    element: &Node<'input, 'input>,
297    errors: &mut Vec<E>,
298) -> Option<Parsed<String>>
299where
300    E: From<ParseError>,
301{
302    let mut parsed = None;
303
304    for child in element.children() {
305        if child.is_text() && parsed.is_none() {
306            if let Some(value) = child.text() {
307                parsed = Some(Parsed {
308                    range: child.range(),
309                    value,
310                });
311            }
312        } else {
313            unexpected_element(child, errors);
314        }
315    }
316
317    if let Some(parsed) = parsed {
318        let value = parsed.value.trim_ascii();
319
320        if value.is_empty() {
321            errors.push(ParseError::StringEmpty {
322                value: element.range().into(),
323            }.into());
324
325            None
326        } else {
327            Some(Parsed {
328                range: parsed.range,
329                value: value.to_owned(),
330            })
331        }
332    } else {
333        errors.push(ParseError::StringEmpty {
334            value: element.range().into(),
335        }.into());
336
337        None
338    }
339}
340
341/// Raise an 'Unexpected element' error
342pub fn unexpected_element<'input, E>(
343    element: Node<'input, 'input>,
344    errors: &mut Vec<E>,
345)
346where
347    E: From<ParseError>,
348{
349    errors.push(ParseError::UnexpectedElement {
350        unexpected: element.range().into(),
351    }.into());
352}
353
354/// Raise an 'Unexpected element' error
355pub fn unexpected_element_range<E>(
356    range: Range<usize>,
357    errors: &mut Vec<E>,
358)
359where
360    E: From<ParseError>,
361{
362    errors.push(ParseError::UnexpectedElement {
363        unexpected: range.into(),
364    }.into());
365}