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