use std::sync::Arc;
use crate::error::Result;
use crate::event::{XmlEvent, XmlEventHandler};
use super::skeleton::{DocumentSkeleton, ElementSkeleton};
pub(crate) struct SkeletonBuilder {
pub(crate) skeleton: DocumentSkeleton,
stack: Vec<usize>,
}
impl SkeletonBuilder {
pub fn new() -> Self {
Self {
skeleton: DocumentSkeleton::new(),
stack: Vec::with_capacity(64),
}
}
pub fn into_skeleton(self) -> DocumentSkeleton {
self.skeleton
}
}
impl XmlEventHandler for SkeletonBuilder {
fn handle(&mut self, event: &XmlEvent) -> Result<()> {
match event {
XmlEvent::StartElement {
name,
prefix,
line,
column,
..
} => {
let node = ElementSkeleton::new(
Arc::clone(name),
prefix.as_ref().map(Arc::clone),
*line,
*column,
);
let node_index = self.skeleton.nodes.len();
self.skeleton.nodes.push(node);
if let Some(&parent_idx) = self.stack.last() {
if let Some(parent) = self.skeleton.nodes.get_mut(parent_idx) {
parent.increment_child(name.as_ref());
parent.children_indices.push(node_index);
}
} else {
self.skeleton.root_index = Some(node_index);
}
self.stack.push(node_index);
}
XmlEvent::EndElement { .. } => {
self.stack.pop();
}
XmlEvent::Text(text) | XmlEvent::CData(text) => {
if let Some(¤t_idx) = self.stack.last() {
if let Some(current) = self.skeleton.nodes.get_mut(current_idx) {
current.text_content.push_str(text);
}
}
}
_ => {}
}
Ok(())
}
fn finish(&mut self) -> Result<()> {
Ok(())
}
fn as_any(self: Box<Self>) -> Box<dyn std::any::Any> {
self
}
}