use crate::*; use std::sync::Arc; /// Represents an XML attribute name that is in the process of being parsed #[derive(Clone, Debug)] pub struct AttributeName { buffer: String, element: Arc, used_attributes: Vec, } impl AttributeName { pub fn new(first_char: char, element: Arc) -> Self { Self { buffer: first_char.to_string(), element, used_attributes: Vec::new(), } } pub fn new_with_used(first_char: char, element: Arc, used_attributes: Vec) -> Self { Self { buffer: first_char.to_string(), element, used_attributes, } } pub fn append(mut self, c: char) -> Vec { if c == '=' { // Check if we've matched a valid attribute name if let Some(attributes) = &self.element.xs_complex_type.xs_attribute { if let Some(attribute) = attributes .iter() .find(|attribute| attribute.name == self.buffer) { // Check if this attribute has already been used if self.used_attributes.contains(&attribute) { return vec![]; } // Add this attribute to the used set self.used_attributes.push(attribute.clone()); return vec![Token::AttributeEquals(AttributeEquals::new( Arc::clone(&self.element), self.used_attributes, ))]; } } return vec![]; } else if c.is_whitespace() { // Check if we've matched a valid attribute name and allow whitespace after it if let Some(attributes) = &self.element.xs_complex_type.xs_attribute { if attributes .iter() .any(|attribute| attribute.name == self.buffer) { // Check if this attribute has already been used if self.used_attributes.iter().filter(|attribute| attribute.name == self.buffer).next().is_some() { return vec![]; } return vec![Token::AttributeName(self)]; } } return vec![]; } else { // Add character to buffer and check if we're still building a valid attribute name let new_buffer = self.buffer.clone() + &c.to_string(); if let Some(attributes) = &self.element.xs_complex_type.xs_attribute { // Check if any attribute name starts with our buffer if attributes .iter() .any(|attribute| attribute.name.starts_with(&new_buffer)) { return vec![Token::AttributeName(AttributeName { buffer: new_buffer, element: Arc::clone(&self.element), used_attributes: self.used_attributes, })]; } } // Character doesn't match what we expect for this attribute name return vec![]; } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_valid_attribute_name() { let values = [ "