nv-xml 0.1.3

A very light weight xml library
Documentation
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 last remaining element
                        {return Ok(finished_element_builder.build())}
                    else //pop parent from queue and add this element
                        {
                            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");
    }
}