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