use {XmlElement, XmlElementBuilder};
use xml::reader::{XmlEvent, EventReader};
use std::io::BufReader;
#[derive(Debug, PartialEq)]
pub enum ParseError
{
MalformedXml,
}
#[derive(Debug)]
pub struct XmlParser;
impl XmlParser
{
pub fn parse(data : &str) -> Result<XmlElement, ParseError>
{
let reader = BufReader::new(data.as_bytes());
let mut builders = Vec::<XmlElementBuilder>::new();
for event in EventReader::new(reader).into_iter().filter_map(|e| e.ok())
{
if Self::is_start_event(&event)
{
builders.push(XmlElementBuilder::new(event));
}
else if Self::is_data_event(&event)
{
builders.last_mut().map(|b| b.add_data(event));
}
else if Self::is_end_event(&event)
{
let finished_element_builder = builders.pop().unwrap();
if builders.is_empty() {return Ok(finished_element_builder.build())}
else {
let mut parent = builders.last_mut().unwrap();
parent.add_child(finished_element_builder);}
}
}
Err(ParseError::MalformedXml)
}
fn is_start_event(event : &XmlEvent) -> bool
{
match event
{
&XmlEvent::StartElement{..} => true,
_ => false
}
}
fn is_end_event(event : &XmlEvent) -> bool
{
match event
{
&XmlEvent::EndElement{..} => true,
_ => false
}
}
fn is_data_event(event: &XmlEvent) -> bool
{
match event
{
&XmlEvent::Characters(_) => true,
_ => false
}
}
}
#[cfg(test)]
mod xml_parser_tests
{
use super::*;
#[test]
fn correct_number_of_elements_test() -> ()
{
let data = "<data/>";
let element = XmlParser::parse(data).unwrap();
assert_eq!(element.children().len(), 0);
}
#[test]
fn can_parse() -> ()
{
let data = "<data/>";
let element = XmlParser::parse(data).unwrap();
assert_eq!(element.name(), "data");
}
#[test]
fn can_parse_nesting() -> ()
{
let data = "<data><something/></data>";
let element = XmlParser::parse(data).unwrap();
assert_eq!(element.name(), "data");
assert_eq!(element.children_with_name("something").len(), 1);
}
#[test]
fn can_parse_loads_of_nesting() -> ()
{
let data = "<data><something/><something/><new_thing><something/></new_thing></data>";
let element = XmlParser::parse(data).unwrap();
assert_eq!(element.name(), "data");
assert_eq!(element.children_with_name("something").len(), 2);
let new_children = element.children_with_name("new_thing");
assert_eq!(new_children.len(), 1);
assert_eq!(new_children.first().unwrap().children_with_name("something").len(), 1);
}
#[test]
fn bad_xml_test() -> ()
{
let data = "<data>";
let element = XmlParser::parse(data);
assert_eq!(element.unwrap_err(), ParseError::MalformedXml);
}
#[test]
fn can_parse_content() -> ()
{
let data = "<data>something</data>";
let element = XmlParser::parse(data).unwrap();
assert_eq!(element.data().unwrap(), "something");
}
}