/// elements resemble a final tree, including inherited namespace information use std::{ collections::{HashMap, HashSet, VecDeque}, str::FromStr, }; use tracing::trace; use crate::{ error::{DeserializeError, Error}, Result, }; pub type DeserializeResult = std::result::Result; pub trait FromElement: Sized { fn from_element(element: Element) -> DeserializeResult; } pub trait IntoElement { fn builder(&self) -> ElementBuilder; fn into_element(&self) -> Element { self.builder().build().unwrap() } fn get_content(&self) -> VecDeque { let element = self.into_element(); element.content } } // when are namespaces names chosen then if they are automatically calculated // namespaces are held by readers and writers. #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct NamespaceDeclaration { pub prefix: Option, pub namespace: String, } // names are qualified, they contain a reference to the namespace (held within the reader/writer) #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct Name { pub namespace: Option, pub local_name: String, } #[derive(Debug, Clone)] pub enum Content { Element(Element), Text(String), PI, Comment(String), } // should this be a trait? #[derive(Debug, Clone)] pub struct Element { pub name: Name, // namespace: Name, // each element once created contains the qualified namespace information for that element // the name contains the qualified namespace so this is unnecessary // namespace: String, // hashmap of explicit namespace declarations on the element itself only // possibly not needed as can be calculated at write time depending on context and qualified namespace, and for reading, element validity and namespaces are kept track of by the reader. // change this to custom namespace declarations only, so you can override the definition of namespaces if you wish pub namespace_declaration_overrides: HashSet, // attributes can be in a different namespace than the element. how to make sure they are valid? // maybe include the namespace instead of or with the prefix // you can calculate the prefix from the namespaced name and the current writer context // you can validate the prefix and calculate the namespace from the current reader context // this results in readers and writers being able to return qualification errors as they aren't able to create elements until every part is qualified. pub attributes: HashMap, // TODO: make a hashmap maybe? to be able to address parts of the content individually pub content: VecDeque, } impl Element { pub fn identify(&self) -> (Option<&str>, &str) { (self.name.namespace.as_deref(), &self.name.local_name) } pub fn check_name(&self, name: &str) -> DeserializeResult<()> { if self.name.local_name == name { Ok(()) } else { return Err(DeserializeError::IncorrectName { expected: name.to_string(), found: self.name.local_name.clone(), }); } } pub fn check_namespace(&self, namespace: &str) -> DeserializeResult<()> { if self.name.namespace.as_deref() == Some(namespace) { return Ok(()); } else { if let Some(actual_namespace) = &self.name.namespace { return Err(DeserializeError::IncorrectNamespace { expected: namespace.to_string(), found: actual_namespace.clone(), }); } else { return Err(DeserializeError::Unqualified { expected: namespace.to_string(), }); } } } pub fn attribute_opt(&mut self, att_name: &str) -> DeserializeResult> { if let Some(att_value) = self.attributes.remove(&Name { namespace: None, local_name: att_name.to_string(), }) { let value = ::from_str(&att_value) .map_err(|_| DeserializeError::FromStr(att_value))?; return Ok(Some(value)); } else { return Ok(None); } } pub fn attribute_opt_namespaced( &mut self, att_name: &str, att_namespace: &str, ) -> DeserializeResult> { if let Some(att_value) = self.attributes.remove(&Name { namespace: Some(att_namespace.to_string()), local_name: att_name.to_string(), }) { let value = ::from_str(&att_value) .map_err(|_| DeserializeError::FromStr(att_value))?; return Ok(Some(value)); } else { return Ok(None); } } pub fn attribute(&mut self, att_name: &str) -> DeserializeResult { let name = Name { namespace: None, local_name: att_name.to_string(), }; if let Some(att_value) = self.attributes.remove(&name) { let value = ::from_str(&att_value) .map_err(|_| DeserializeError::FromStr(att_value))?; return Ok(value); } else { return Err(DeserializeError::MissingAttribute(name)); } } pub fn attribute_namespaced( &mut self, att_name: &str, att_namespace: &str, ) -> DeserializeResult { let name = Name { namespace: Some(att_namespace.to_string()), local_name: att_name.to_string(), }; if let Some(att_value) = self.attributes.remove(&name) { let value = ::from_str(&att_value) .map_err(|_| DeserializeError::FromStr(att_value))?; return Ok(value); } else { return Err(DeserializeError::MissingAttribute(name)); } } pub fn no_more_attributes(self) -> DeserializeResult { if self.attributes.is_empty() { Ok(self) } else { Err(DeserializeError::UnexpectedAttributes(self.attributes)) } } // for xs:any pub fn child_one(&mut self) -> DeserializeResult { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(element) => ::from_element(element.clone()).is_ok(), Content::Text(_) => false, Content::PI => false, Content::Comment(_) => false, }) { let element = self.content.remove(position).unwrap(); if let Content::Element(e) = element { return ::from_element(e); } else { return Err(DeserializeError::MissingChild); } } else { return Err(DeserializeError::MissingChild); } } pub fn child_opt(&mut self) -> DeserializeResult> { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(element) => ::from_element(element.clone()).is_ok(), Content::Text(_) => false, Content::PI => false, Content::Comment(_) => false, }) { let element = self.content.remove(position).unwrap(); if let Content::Element(e) = element { return Ok(Some(::from_element(e)?)); } else { return Err(DeserializeError::MissingChild); } } else { return Ok(None); } } pub fn children(&mut self) -> DeserializeResult> { let (children, rest): (VecDeque<_>, VecDeque<_>) = self .content .clone() .into_iter() .partition(|content| match content { Content::Element(element) => { ::from_element(element.clone()).is_ok() } Content::Text(_) => false, Content::PI => false, Content::Comment(_) => false, }); self.content = rest; let children: Vec = children .into_iter() .map(|content| { let child = match content { Content::Element(element) => ::from_element(element).ok(), Content::Text(_) => None, Content::PI => None, Content::Comment(_) => None, } .unwrap(); child }) .collect(); Ok(children) } pub fn value(&mut self) -> DeserializeResult { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(_) => false, Content::Text(s) => ::from_str(s).is_ok(), Content::PI => false, Content::Comment(_) => false, }) { let element = self.content.remove(position).unwrap(); if let Content::Text(v) = element { return Ok(::from_str(&v).ok().unwrap()); } else { panic!("infallible") } } else { return Err(DeserializeError::MissingValue); } } pub fn value_opt(&mut self) -> DeserializeResult> { if let Some(position) = self.content.iter().position(|content| match content { Content::Element(_) => false, Content::Text(s) => ::from_str(s).is_ok(), Content::PI => false, Content::Comment(_) => false, }) { let element = self.content.remove(position).unwrap(); if let Content::Text(v) = element { return Ok(::from_str(&v).ok()); } else { panic!("infallible") } } else { return Ok(None); } } // for xs:sequence pub fn pop_child_one(&mut self) -> DeserializeResult { loop { let child = self .content .pop_front() .ok_or(DeserializeError::MissingChild)?; match child { Content::Element(element) => return Ok(::from_element(element)?), Content::Text(_) => { return Err(DeserializeError::UnexpectedContent(self.content.clone())) } Content::PI => {} Content::Comment(_) => {} } } } pub fn pop_child_opt(&mut self) -> DeserializeResult> { loop { let child = self.content.pop_front(); if let Some(child) = child { match child { Content::Element(element) => { return Ok(Some(::from_element(element)?)) } Content::Text(_) => { return Err(DeserializeError::UnexpectedContent(self.content.clone())) } Content::PI => {} Content::Comment(_) => {} } } else { return Ok(None); } } } pub fn pop_children(&mut self) -> DeserializeResult> { let mut children = Vec::new(); loop { let child = self.content.front(); trace!("child: {:?}", child); if let Some(child) = child { match child { Content::Element(element) => { if let Ok(child) = ::from_element(element.clone()) { trace!("parsed child"); children.push(child); self.content.pop_front(); } else { trace!("failed to parse child"); return Ok(children); } } Content::Text(_) => return Ok(children), Content::PI => { self.content.pop_front(); continue; } Content::Comment(_) => { self.content.pop_front(); continue; } } } else { return Ok(children); } } } pub fn pop_value(&mut self) -> DeserializeResult { loop { let child = self .content .pop_front() .ok_or(DeserializeError::MissingValue)?; match child { Content::Element(_) => { return Err(DeserializeError::UnexpectedContent(self.content.clone())) } Content::Text(t) => { return Ok( ::from_str(&t).map_err(|_| DeserializeError::FromStr(t))? ) } Content::PI => {} Content::Comment(_) => {} } } } pub fn pop_value_opt(&mut self) -> DeserializeResult> { loop { let child = self.content.pop_front(); if let Some(child) = child { match child { Content::Element(_) => { return Err(DeserializeError::UnexpectedContent(self.content.clone())) } Content::Text(t) => { return Ok(Some( ::from_str(&t) .map_err(|_| DeserializeError::FromStr(t))?, )) } Content::PI => {} Content::Comment(_) => {} } } else { return Ok(None); } } } pub fn no_more_content(self) -> DeserializeResult { if self .content .iter() .filter(|content| match content { Content::Element(_) => true, Content::Text(_) => true, Content::PI => false, Content::Comment(_) => false, }) .collect::>() .is_empty() { Ok(self) } else { Err(DeserializeError::UnexpectedContent(self.content)) } } pub fn builder(name: impl ToString, namespace: Option) -> ElementBuilder { ElementBuilder::new(name, namespace) } } pub struct ElementBuilder { name: Name, namespace_declaration_overrides: Vec, attributes: Vec<(Name, String)>, content: Vec, } impl ElementBuilder { pub fn new(name: impl ToString, namespace: Option) -> Self { Self { name: Name { namespace: namespace.map(|namespace| namespace.to_string()), local_name: name.to_string(), }, namespace_declaration_overrides: Vec::new(), attributes: Vec::new(), content: Vec::new(), } } pub fn push_namespace_declaration_override( mut self, prefix: Option, namespace: impl ToString, ) -> Self { self.namespace_declaration_overrides .push(NamespaceDeclaration { prefix: prefix.map(|prefix| prefix.to_string()), namespace: namespace.to_string(), }); self } pub fn push_attribute(mut self, name: N, value: V) -> Self { self.attributes.push(( // TODO: make sure name is a valid name, same for prefixes Name { namespace: None, local_name: name.to_string(), }, value.to_string(), )); self } pub fn push_attribute_namespaced( mut self, namespace: impl ToString, name: impl ToString, value: impl ToString, ) -> Self { self.attributes.push(( Name { namespace: Some(namespace.to_string()), local_name: name.to_string(), }, value.to_string(), )); self } pub fn push_child(mut self, child: impl IntoElement) -> Self { self.content.push(ContentBuilder::Element(child.builder())); self } pub fn push_text(mut self, text: impl ToString) -> Self { self.content.push(ContentBuilder::Text(text.to_string())); self } pub fn push_attribute_opt(self, name: impl ToString, value: Option) -> Self { if let Some(value) = value { self.push_attribute(name, value) } else { self } } pub fn push_attribute_opt_namespaced( self, namespace: impl ToString, name: impl ToString, value: Option, ) -> Self { if let Some(value) = value { self.push_attribute_namespaced(namespace, name, value) } else { self } } pub fn push_child_opt(self, child: Option) -> Self { if let Some(child) = child { self.push_child(child) } else { self } } pub fn push_text_opt(self, text: Option) -> Self { if let Some(text) = text { self.push_text(text) } else { self } } pub fn push_content(mut self, content: ContentBuilder) -> Self { self.content.push(content); self } pub fn push_children(self, children: Vec) -> Self { let mut element_builder = self; for child in children { element_builder = element_builder.push_content(child.builder()) } element_builder } pub fn build(&self) -> Result { let mut namespace_declaration_overrides = HashSet::new(); for namespace_declaration in &self.namespace_declaration_overrides { if !namespace_declaration_overrides.insert(namespace_declaration.clone()) { return Err(Error::DuplicateNameSpaceDeclaration( namespace_declaration.clone(), )); } } let mut attributes = HashMap::new(); for (att_name, att_value) in &self.attributes { if attributes .insert(att_name.clone(), att_value.to_string()) .is_some() { // TODO: better error return Err(Error::DuplicateAttribute(att_name.local_name.to_string())); } } let content: Result> = self .content .iter() .map(|content_builder| -> Result { Ok(content_builder.build()?) }) .collect(); let content = content?; Ok(Element { name: self.name.clone(), namespace_declaration_overrides, attributes, content, }) } } pub trait IntoContent { fn into_content(&self) -> Content { self.builder().build().unwrap() } fn builder(&self) -> ContentBuilder; } impl IntoContent for T where T: IntoElement, { fn builder(&self) -> ContentBuilder { ContentBuilder::Element(self.builder()) } } pub trait FromContent: Sized { fn from_content(content: Content) -> DeserializeResult; } pub enum ContentBuilder { Element(ElementBuilder), Text(String), Comment(String), } impl ContentBuilder { pub fn build(&self) -> Result { match self { ContentBuilder::Element(element_builder) => { Ok(Content::Element(element_builder.build()?)) } ContentBuilder::Text(text) => Ok(Content::Text(text.to_string())), ContentBuilder::Comment(s) => Ok(Content::Comment(s.to_string())), } } } pub fn escape_str(s: &str) -> String { let mut string = String::new(); for str in s.split_inclusive(|c| c == '<' || c == '&' || c == '>') { if let Some(str) = str.strip_suffix('<') { if !str.is_empty() { string.push_str(str) } string.push_str("<"); } else if let Some(str) = str.strip_suffix('&') { if !str.is_empty() { string.push_str(str) } string.push_str("&"); } else if let Some(str) = str.strip_suffix('>') { if !str.is_empty() { string.push_str(str) } string.push_str(">"); } else { if !str.is_empty() { string.push_str(str) } } } string } // impl<'s> TryFrom> for Element<'s> { // type Error = Error; // fn try_from(xml_element: xml::Element) -> Result { // match &xml_element { // xml::Element::Empty(empty_elem_tag) => { // let namespace_decl; // let attributes; // empty_elem_tag // .attributes // .into_iter() // .filter(|attribute| matches!(attribute, Attribute::NamespaceDeclaration(_))); // todo!() // } // xml::Element::NotEmpty(stag, content, etag) => todo!(), // } // } // } // example of deriving an element: // #[derive(XMLWrite, XMLRead)] // #[peanuts(xmlns = "jabber:client", xmlns:stream = "http://etherx.jabber.org/streams", prefix = "stream")] // pub struct Stream { // from: JID, // id: String, // to: JID, // version: String, // #[peanuts(namespace = "http://www.w3.org/XML/1998/namespace")] // lang: Lang, // } // note: if an element name has a prefix all unprefixed attributes are qualified by the namespace of the prefix, so in this example from's Name's namespace would be "http://etherx.jabber.org/streams"