use std::ptr::null_mut;
use crate::ParseError;
use crate::SaxElement;
use super::Cursor;
use super::Document;
use super::Node;
use super::error::description;
pub struct DocumentBuilder {
doc: Option<Document>,
node: *mut Node,
size_hint: Option<usize>,
}
impl DocumentBuilder {
pub fn new() -> Self {
DocumentBuilder {
doc: None,
node: null_mut(),
size_hint: None,
}
}
pub fn with_size_hint(size_hint: usize) -> Self {
DocumentBuilder {
doc: None,
node: null_mut(),
size_hint: Some(size_hint),
}
}
pub fn append_element(&mut self, element: &SaxElement) -> Result<(), ParseError> {
match &self.doc {
None => match element {
SaxElement::StartTag(name) => {
let doc = match self.size_hint {
Some(size_hint) => Document::with_size_hint(name, size_hint)?,
None => Document::new(name)?,
};
self.node = doc.root().get_node_ptr();
self.doc = Some(doc);
}
_ => return Err(ParseError::BadXml(description::NO_START_TAG)),
},
Some(doc) => match element {
SaxElement::StartTag(name) => {
let new_tag = Cursor::new(self.node, &doc.arena).insert_tag(name)?;
self.node = new_tag.get_node_ptr();
}
SaxElement::Attribute(name, value) => {
Cursor::new(self.node, &doc.arena).insert_attribute(name, value)?;
}
SaxElement::StartTagContent => {}
SaxElement::StartTagEmpty => {
self.node = Cursor::new(self.node, &doc.arena).parent().get_node_ptr();
}
SaxElement::CData(cdata) => {
Cursor::new(self.node, &doc.arena).insert_cdata(cdata)?;
}
SaxElement::EndTag(name) => {
if name != &Cursor::new(self.node, &doc.arena).name() {
return Err(ParseError::BadXml(description::TAG_MISMATCH));
}
self.node = Cursor::new(self.node, &doc.arena).parent().get_node_ptr();
}
},
}
Ok(())
}
pub fn peek(&self) -> Option<&Document> {
self.doc.as_ref()
}
pub fn take(&mut self) -> Option<Document> {
self.doc.take()
}
pub fn replace(&mut self, doc: Document) -> Option<Document> {
self.doc.replace(doc)
}
}
impl Default for DocumentBuilder {
fn default() -> Self {
Self::new()
}
}