tree_builder.rs

  1// Copyright (c) 2022 Astro <astro@spaceboyz.net>
  2
  3//! SAX events to DOM tree conversion
  4
  5use crate::prefixes::{Prefix, Prefixes};
  6use crate::{Element, Error};
  7use alloc::collections::BTreeMap;
  8use alloc::format;
  9use alloc::string::String;
 10use alloc::vec::Vec;
 11use rxml::RawEvent;
 12
 13/// Tree-building parser state
 14pub struct TreeBuilder {
 15    next_tag: Option<(Prefix, String, Prefixes, BTreeMap<String, String>)>,
 16    /// Parsing stack
 17    stack: Vec<Element>,
 18    /// Namespace set stack by prefix
 19    prefixes_stack: Vec<Prefixes>,
 20    /// Document root element if finished
 21    pub root: Option<Element>,
 22}
 23
 24impl Default for TreeBuilder {
 25    fn default() -> Self {
 26        Self::new()
 27    }
 28}
 29
 30impl TreeBuilder {
 31    /// Create a new one
 32    #[must_use]
 33    pub fn new() -> Self {
 34        TreeBuilder {
 35            next_tag: None,
 36            stack: Vec::new(),
 37            prefixes_stack: Vec::new(),
 38            root: None,
 39        }
 40    }
 41
 42    /// Allow setting prefixes stack.
 43    ///
 44    /// Useful to provide knowledge of namespaces that would have been declared on parent elements
 45    /// not present in the reader.
 46    #[must_use]
 47    pub fn with_prefixes_stack(mut self, prefixes_stack: Vec<Prefixes>) -> Self {
 48        self.prefixes_stack = prefixes_stack;
 49        self
 50    }
 51
 52    /// Stack depth
 53    #[must_use]
 54    pub fn depth(&self) -> usize {
 55        self.stack.len()
 56    }
 57
 58    /// Get the top-most element from the stack but don't remove it
 59    #[must_use]
 60    pub fn top(&mut self) -> Option<&Element> {
 61        self.stack.last()
 62    }
 63
 64    /// Pop the top-most element from the stack
 65    fn pop(&mut self) -> Option<Element> {
 66        self.prefixes_stack.pop();
 67        self.stack.pop()
 68    }
 69
 70    /// Unshift the first child of the top element
 71    pub fn unshift_child(&mut self) -> Option<Element> {
 72        let depth = self.stack.len();
 73        if depth > 0 {
 74            self.stack[depth - 1].unshift_child()
 75        } else {
 76            None
 77        }
 78    }
 79
 80    /// Lookup XML namespace declaration for given prefix (or no prefix)
 81    #[must_use]
 82    fn lookup_prefix(&self, prefix: &Option<String>) -> Option<&str> {
 83        for nss in self.prefixes_stack.iter().rev() {
 84            if let Some(ns) = nss.get(prefix) {
 85                return Some(ns);
 86            }
 87        }
 88
 89        None
 90    }
 91
 92    fn process_end_tag(&mut self) {
 93        if let Some(el) = self.pop() {
 94            if self.depth() > 0 {
 95                let top = self.stack.len() - 1;
 96                self.stack[top].append_child(el);
 97            } else {
 98                self.root = Some(el);
 99            }
100        }
101    }
102
103    fn process_text(&mut self, text: String) {
104        if self.depth() > 0 {
105            let top = self.stack.len() - 1;
106            self.stack[top].append_text(text);
107        }
108    }
109
110    /// Process an event that you got out of a `RawParser`.
111    pub fn process_event(&mut self, event: RawEvent) -> Result<(), Error> {
112        match event {
113            RawEvent::XmlDeclaration(_, _) => {}
114
115            RawEvent::ElementHeadOpen(_, (prefix, name)) => {
116                self.next_tag = Some((
117                    prefix.map(|prefix| prefix.as_str().to_owned()),
118                    name.as_str().to_owned(),
119                    Prefixes::default(),
120                    BTreeMap::new(),
121                ));
122            }
123
124            RawEvent::Attribute(_, (prefix, name), value) => {
125                if let Some((_, _, ref mut prefixes, ref mut attrs)) = self.next_tag.as_mut() {
126                    match (prefix, name) {
127                        (None, xmlns) if xmlns == "xmlns" => prefixes.insert(None, value),
128                        (Some(xmlns), prefix) if xmlns.as_str() == "xmlns" => {
129                            prefixes.insert(Some(prefix.as_str().to_owned()), value);
130                        }
131                        (Some(prefix), name) => {
132                            attrs.insert(format!("{prefix}:{name}"), value.as_str().to_owned());
133                        }
134                        (None, name) => {
135                            attrs.insert(name.as_str().to_owned(), value.as_str().to_owned());
136                        }
137                    }
138                }
139            }
140
141            RawEvent::ElementHeadClose(_) => {
142                if let Some((prefix, name, prefixes, attrs)) = self.next_tag.take() {
143                    self.prefixes_stack.push(prefixes.clone());
144
145                    let namespace = self
146                        .lookup_prefix(&prefix.map(|prefix| prefix.as_str().to_owned()))
147                        .ok_or(Error::MissingNamespace)?
148                        .to_owned();
149                    let el = Element::new(name.to_owned(), namespace, prefixes, attrs, Vec::new());
150                    self.stack.push(el);
151                }
152            }
153
154            RawEvent::ElementFoot(_) => self.process_end_tag(),
155
156            RawEvent::Text(_, text) => self.process_text(text.as_str().to_owned()),
157        }
158
159        Ok(())
160    }
161}