use std::str;
use xmlparser::{
self,
FromSpan,
StrSpan,
};
use {
AttributeId,
ElementId,
};
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Name<'a, T> {
Xml(&'a str),
Svg(T),
}
#[derive(PartialEq, Debug, Clone, Copy)]
pub struct QName<'a, T> {
pub prefix: &'a str,
pub local: Name<'a, T>,
}
impl<'a, T> QName<'a, T> {
pub fn new(prefix: &'a str, local: Name<'a, T>) -> Self {
QName {
prefix: prefix,
local: local,
}
}
}
pub type TagName<'a> = QName<'a, ElementId>;
pub type AttrName<'a> = QName<'a, AttributeId>;
type StrSpanPair<'a> = (StrSpan<'a>, StrSpan<'a>);
impl<'a> From<StrSpanPair<'a>> for TagName<'a> {
fn from(v: StrSpanPair<'a>) -> Self {
let v1 = v.1.to_str();
let local = match ElementId::from_name(v1) {
Some(id) => Name::Svg(id),
None => Name::Xml(v1),
};
QName::new(v.0.to_str(), local)
}
}
impl<'a> From<StrSpanPair<'a>> for AttrName<'a> {
fn from(v: StrSpanPair<'a>) -> Self {
let v1 = v.1.to_str();
let local = match AttributeId::from_name(v1) {
Some(id) => Name::Svg(id),
None => Name::Xml(v1),
};
QName::new(v.0.to_str(), local)
}
}
#[derive(Debug)]
pub enum Token<'a> {
Declaration(&'a str, Option<&'a str>, Option<&'a str>),
ProcessingInstruction(&'a str, Option<&'a str>),
EntityDeclaration(&'a str, StrSpan<'a>),
Comment(&'a str),
ElementStart(TagName<'a>),
ElementEnd(ElementEnd<'a>),
Attribute(AttrName<'a>, StrSpan<'a>),
Text(StrSpan<'a>),
Cdata(StrSpan<'a>),
Whitespaces(&'a str),
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ElementEnd<'a> {
Open,
Close(TagName<'a>),
Empty,
}
#[allow(missing_debug_implementations)]
pub struct Tokenizer<'a> {
parser: xmlparser::Tokenizer<'a>,
}
impl<'a> FromSpan<'a> for Tokenizer<'a> {
fn from_span(span: StrSpan<'a>) -> Self {
Tokenizer {
parser: xmlparser::Tokenizer::from_span(span),
}
}
}
impl<'a> Iterator for Tokenizer<'a> {
type Item = Result<Token<'a>, xmlparser::Error>;
fn next(&mut self) -> Option<Self::Item> {
let token = match try_opt!(self.parser.next()) {
Ok(t) => t,
Err(e) => return Some(Err(e.into()))
};
let t = match token {
xmlparser::Token::ElementStart(prefix, name) => {
Ok(Token::ElementStart((prefix, name).into()))
}
xmlparser::Token::ElementEnd(end) => {
let svg_end = match end {
xmlparser::ElementEnd::Open => {
ElementEnd::Open
}
xmlparser::ElementEnd::Close(prefix, name) => {
ElementEnd::Close((prefix, name).into())
}
xmlparser::ElementEnd::Empty => {
ElementEnd::Empty
}
};
Ok(Token::ElementEnd(svg_end))
}
xmlparser::Token::Attribute(name, value) => {
Ok(Token::Attribute(name.into(), value))
}
xmlparser::Token::Text(text) => {
Ok(Token::Text(text))
}
xmlparser::Token::Whitespaces(text) => {
Ok(Token::Whitespaces(text.to_str()))
}
xmlparser::Token::Cdata(text) => {
Ok(Token::Cdata(text))
}
xmlparser::Token::Comment(text) => {
Ok(Token::Comment(text.to_str()))
}
xmlparser::Token::EntityDeclaration(name, def) => {
match def {
xmlparser::EntityDefinition::EntityValue(value) => {
Ok(Token::EntityDeclaration(name.to_str(), value))
}
_ => {
return self.next();
}
}
}
xmlparser::Token::Declaration(version, encoding, standalone) => {
Ok(Token::Declaration(
version.to_str(),
encoding.map(|s| s.to_str()),
standalone.map(|s| s.to_str())
))
}
xmlparser::Token::ProcessingInstruction(target, content) => {
Ok(Token::ProcessingInstruction(
target.to_str(),
content.map(|s| s.to_str())
))
}
xmlparser::Token::DtdStart(_, _)
| xmlparser::Token::EmptyDtd(_, _)
| xmlparser::Token::DtdEnd => {
return self.next();
}
};
Some(t)
}
}