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