use super::dom::Attribute;
use super::dom::Node;
use super::namespaces::Namespace;
use super::namespaces::NamespaceRegistry;
use super::xml;
use uexpr::tokenizer::Token;
pub fn parse_tokens<'a>(
namespace_registry: &'a NamespaceRegistry,
default_namespace: &'a Namespace,
tokens: &[Token],
) -> Node<'a> {
let mut nodes: Vec<Node> = Vec::new();
let mut i: usize = 0;
while i < tokens.len() {
match &tokens[i] {
Token::ElementStart => {
i += 1;
let element_result =
parse_element(namespace_registry, default_namespace, &tokens[i..]);
i += element_result.0;
nodes.push(element_result.1);
}
Token::ValueString(data) => {
nodes.push(Node::new_text(data.to_string()));
}
Token::ValueUInt(unsigned_integer) => {
nodes.push(Node::new_text(unsigned_integer.to_string()));
}
Token::ValueInt(integer) => {
nodes.push(Node::new_text(integer.to_string()));
}
Token::ValueFloat(float) => {
nodes.push(Node::new_text(float.to_string()));
}
Token::ValueBool(boolean) => {
if *boolean {
nodes.push(Node::new_text(String::from("T")));
} else {
nodes.push(Node::new_text(String::from("F")));
}
}
_ => {
panic!("Expected a starting token got a {:?} instead.", &tokens[i]);
}
}
i += 1;
}
if nodes.len() == 1 {
return nodes.pop().unwrap();
} else {
return Node::new_document_fragment(nodes);
}
}
fn parse_element<'a>(
namespace_registry: &'a NamespaceRegistry,
parent_namespace: &'a Namespace,
element_tokens: &[Token],
) -> (usize, Node<'a>) {
if element_tokens.len() < 2 {
panic!(
"Minimum number of element_tokens is 2: [Token::ElementLocalName, Token::ElementEnd]"
);
}
let element_namespace: &Namespace;
let local_name: String;
let mut attributes: Vec<Attribute> = Vec::new();
let mut children: Vec<Node> = Vec::new();
let mut i: usize = 0;
match &element_tokens[i] {
Token::ElementPrefix(prefix) => {
match namespace_registry.get(&prefix) {
Some(namespace) => {
element_namespace = namespace;
}
None => panic!("Unknown namespace prefix in Token::ElementPrefix."),
}
i += 1;
}
_ => {
element_namespace = parent_namespace;
}
}
match &element_tokens[i] {
Token::ElementLocalName(name) => {
local_name = name.to_string();
i += 1;
}
_ => panic!("Expected a Token::ElementLocalName but did not get one!"),
}
while i < element_tokens.len() {
match &element_tokens[i] {
Token::ElementStart => {
i += 1;
let child_element_result =
parse_element(namespace_registry, element_namespace, &element_tokens[i..]);
i += child_element_result.0;
children.push(child_element_result.1);
}
Token::ElementEnd => {
return (
i,
Node::new_element(element_namespace, local_name, attributes, children),
);
}
Token::AttributeStart => {
i += 1;
let attribute_result =
parse_attribute(namespace_registry, element_namespace, &element_tokens[i..]);
i += attribute_result.0;
attributes.push(attribute_result.1);
}
Token::ValueString(data) => {
children.push(Node::new_text(data.to_string()));
}
Token::ValueUInt(unsigned_integer) => {
children.push(Node::new_text(unsigned_integer.to_string()));
}
Token::ValueInt(integer) => {
children.push(Node::new_text(integer.to_string()));
}
Token::ValueFloat(float) => {
children.push(Node::new_text(float.to_string()));
}
Token::ValueBool(boolean) => {
if *boolean {
children.push(Node::new_text(String::from("T")));
} else {
children.push(Node::new_text(String::from("F")));
}
}
_ => {
panic!(
"Expected a follow up to Token::ElementLocalName but got a {:?} instead.",
element_tokens[i]
);
}
}
i += 1;
}
panic!("Expected a Token::ElementEnd but ran out of tokens instead.");
}
fn parse_attribute<'a>(
namespace_registry: &'a NamespaceRegistry,
owner_element_namespace: &'a Namespace,
attribute_tokens: &[Token],
) -> (usize, Attribute<'a>) {
if attribute_tokens.len() < 2 {
panic!("Minimum number of attribute_tokens is 2: [Token::AttributeLocalName, Token::AttributeEnd]");
}
let attribute_namespace: &Namespace;
let local_name: String;
let mut value: String = String::new();
let mut i: usize = 0;
match &attribute_tokens[i] {
Token::AttributePrefix(prefix) => {
match namespace_registry.get(&prefix) {
Some(namespace) => {
attribute_namespace = namespace;
}
None => panic!("Unknown namespace prefix in Token::AttributePrefix."),
}
i += 1;
}
_ => {
attribute_namespace = owner_element_namespace;
}
}
match &attribute_tokens[i] {
Token::AttributeLocalName(name) => {
local_name = name.to_string();
i += 1;
}
_ => panic!(
"Expected a Token::AttributeLocalName but got a {:?} instead.",
attribute_tokens[i]
),
}
while i < attribute_tokens.len() {
match &attribute_tokens[i] {
Token::ValueString(data) => {
if value.len() > 0 {
value.push_str(" ");
}
value.push_str(&data);
}
Token::ValueUInt(unsigned_integer) => {
if value.len() > 0 {
value.push_str(" ");
}
value.push_str(&unsigned_integer.to_string());
}
Token::ValueInt(integer) => {
if value.len() > 0 {
value.push_str(" ");
}
value.push_str(&integer.to_string());
}
Token::ValueFloat(float) => {
if value.len() > 0 {
value.push_str(" ");
}
value.push_str(&float.to_string());
}
Token::ValueBool(boolean) => {
if value.len() > 0 {
value.push_str(" ");
}
if *boolean {
value.push_str("true");
} else {
value.push_str("false");
}
}
Token::AttributeEnd => match *attribute_namespace {
xml::NAMESPACE => return (i, xml::attribute_factory(local_name, value)),
_ => return (i, Attribute::new(attribute_namespace, local_name, value)),
},
_ => {
panic!(
"Expected a follow up to Token::AttributeLocalName but got a {:?} instead.",
attribute_tokens[i]
);
}
}
i += 1;
}
panic!("Expected a Token::AttributeEnd but ran out of tokens instead.");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_unprefixed_attribute() {
let nsr: NamespaceRegistry = NamespaceRegistry::new();
let ns: &Namespace = nsr.get("xhtml").unwrap();
let tokens: Vec<Token> = vec![
Token::AttributeLocalName("title".to_string()),
Token::ValueString("my value".to_string()),
Token::AttributeEnd,
];
let expected = Attribute::new(ns, "title".to_string(), "my value".to_string());
assert_eq!(parse_attribute(&nsr, ns, &tokens[..]).1, expected);
}
#[test]
fn parse_prefixed_attribute_current_namespace() {
let nsr: NamespaceRegistry = NamespaceRegistry::new();
let ns: &Namespace = nsr.get("xhtml").unwrap();
let tokens: Vec<Token> = vec![
Token::AttributePrefix("xhtml".to_string()),
Token::AttributeLocalName("title".to_string()),
Token::ValueString("my value".to_string()),
Token::AttributeEnd,
];
let expected = Attribute::new(ns, "title".to_string(), "my value".to_string());
assert_eq!(parse_attribute(&nsr, ns, &tokens[..]).1, expected);
}
#[test]
fn parse_prefixed_attribute_different_namespace() {
let nsr: NamespaceRegistry = NamespaceRegistry::new();
let ns: &Namespace = nsr.get("xhtml").unwrap();
let fns: &Namespace = nsr.get("svg").unwrap();
let tokens: Vec<Token> = vec![
Token::AttributePrefix("svg".to_string()),
Token::AttributeLocalName("cx".to_string()),
Token::ValueString("50".to_string()),
Token::AttributeEnd,
];
let expected = Attribute::new(fns, "cx".to_string(), "50".to_string());
assert_eq!(parse_attribute(&nsr, ns, &tokens[..]).1, expected);
}
#[test]
fn parse_unprefixed_empty_element() {
let nsr: NamespaceRegistry = NamespaceRegistry::new();
let ns: &Namespace = nsr.get("xhtml").unwrap();
let tokens: Vec<Token> = vec![Token::ElementLocalName("br".to_string()), Token::ElementEnd];
let expected = Node::new_element(ns, "br".to_string(), vec![], vec![]);
assert_eq!(parse_element(&nsr, ns, &tokens[..]).1, expected);
}
#[test]
fn parse_prefixed_empty_element_current_namespace() {
let nsr: NamespaceRegistry = NamespaceRegistry::new();
let ns: &Namespace = nsr.get("xhtml").unwrap();
let tokens: Vec<Token> = vec![
Token::ElementPrefix("xhtml".to_string()),
Token::ElementLocalName("br".to_string()),
Token::ElementEnd,
];
let expected = Node::new_element(ns, "br".to_string(), vec![], vec![]);
assert_eq!(parse_element(&nsr, ns, &tokens[..]).1, expected);
}
#[test]
fn parse_prefixed_empty_element_different_namespace() {
let nsr: NamespaceRegistry = NamespaceRegistry::new();
let ns: &Namespace = nsr.get("xhtml").unwrap();
let fns: &Namespace = nsr.get("svg").unwrap();
let tokens: Vec<Token> = vec![
Token::ElementPrefix("svg".to_string()),
Token::ElementLocalName("circle".to_string()),
Token::ElementEnd,
];
let expected = Node::new_element(fns, "circle".to_string(), vec![], vec![]);
assert_eq!(parse_element(&nsr, ns, &tokens[..]).1, expected);
}
#[test]
fn parse_unprefixed_empty_element_local_attribute() {
let nsr: NamespaceRegistry = NamespaceRegistry::new();
let ns: &Namespace = nsr.get("xhtml").unwrap();
let tokens: Vec<Token> = vec![
Token::ElementLocalName("p".to_string()),
Token::AttributeStart,
Token::AttributeLocalName("title".to_string()),
Token::ValueString("My tooltip.".to_string()),
Token::AttributeEnd,
Token::ElementEnd,
];
let attr = Attribute::new(ns, "title".to_string(), "My tooltip.".to_string());
let expected = Node::new_element(ns, "p".to_string(), vec![attr], vec![]);
assert_eq!(parse_element(&nsr, ns, &tokens[..]).1, expected);
}
}