use std::{collections::HashSet, str::FromStr}; use futures::Sink; use tokio::io::AsyncWrite; use crate::{ element::{Element, Name, NamespaceDeclaration}, error::Error, xml::{self, composers::Composer, parsers_complete::Parser, ETag}, Result, }; // pub struct Writer { pub struct Writer { inner: W, depth: Vec, namespace_declarations: Vec>, } impl Writer { pub async fn write(&mut self, element: Element) -> Result<()> { todo!() } pub async fn write_start(&mut self, element: Element) -> Result<()> { let namespace_declarations_stack: Vec<_> = self .namespace_declarations .iter() .flatten() .chain(&element.namespace_declarations) .collect(); let prefix; if let Some(namespace) = &element.name.namespace { let name_namespace_declaration = namespace_declarations_stack .iter() .rfind(|namespace_declaration| namespace_declaration.namespace == *namespace) .ok_or(Error::UndeclaredNamespace(namespace.clone()))?; prefix = name_namespace_declaration.prefix.as_ref(); } else { prefix = None } let name; if let Some(prefix) = &prefix { name = xml::QName::PrefixedName(xml::PrefixedName { prefix: xml::Prefix::parse_full(prefix)?, local_part: xml::LocalPart::parse_full(&element.name.local_name)?, }) } else { name = xml::QName::UnprefixedName(xml::UnprefixedName::parse_full( &element.name.local_name, )?) } let mut attributes = Vec::new(); for namespace_declaration in &element.namespace_declarations { let ns_name = namespace_declaration .prefix .as_ref() .map(|prefix| -> Result<_> { Ok(xml::NSAttName::PrefixedAttName( xml::PrefixedAttName::parse_full(&prefix)?, )) }) .unwrap_or(Ok(xml::NSAttName::DefaultAttName))?; let value = xml::AttValue::from(namespace_declaration.namespace.as_str()); let xml_attribute = xml::Attribute::NamespaceDeclaration { ns_name, value }; attributes.push(xml_attribute); } for (name, value) in &element.attributes { let prefix; if let Some(namespace) = &name.namespace { let name_namespace_declaration = namespace_declarations_stack .iter() .rfind(|namespace_declaration| namespace_declaration.namespace == *namespace) .ok_or(Error::UndeclaredNamespace(namespace.clone()))?; prefix = name_namespace_declaration.prefix.as_ref(); } else { prefix = None } let att_name; if let Some(prefix) = &prefix { att_name = xml::QName::PrefixedName(xml::PrefixedName { prefix: xml::Prefix::parse_full(prefix)?, local_part: xml::LocalPart::parse_full(&element.name.local_name)?, }) } else { att_name = xml::QName::UnprefixedName(xml::UnprefixedName::parse_full( &element.name.local_name, )?) } let value = xml::AttValue::from(value.as_str()); let xml_attribute = xml::Attribute::Attribute { name: att_name, value, }; attributes.push(xml_attribute); } let s_tag = xml::STag { name, attributes }; s_tag.write(&mut self.inner).await?; self.depth.push(element.name); self.namespace_declarations .push(element.namespace_declarations); Ok(()) } pub async fn write_end(&mut self) -> Result<()> { if let Some(name) = &self.depth.pop() { let e_tag; let namespace_declarations_stack: Vec<_> = self.namespace_declarations.iter().flatten().collect(); let prefix; if let Some(namespace) = &name.namespace { let name_namespace_declaration = namespace_declarations_stack .iter() .rfind(|namespace_declaration| namespace_declaration.namespace == *namespace) .ok_or(Error::UndeclaredNamespace(namespace.clone()))?; prefix = name_namespace_declaration.prefix.as_ref(); } else { prefix = None } if let Some(prefix) = &prefix { e_tag = xml::ETag { name: xml::QName::PrefixedName(xml::PrefixedName { prefix: xml::Prefix::parse_full(prefix)?, local_part: xml::LocalPart::parse_full(&name.local_name)?, }), }; } else { e_tag = xml::ETag { name: xml::QName::UnprefixedName(xml::UnprefixedName::parse_full( &name.local_name, )?), }; } e_tag.write(&mut self.inner).await?; self.namespace_declarations.pop(); Ok(()) } else { return Err(Error::NotInElement("".to_string())); } } } impl> Sink for Writer { type Error = Error; fn poll_ready( self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { todo!() } fn start_send(self: std::pin::Pin<&mut Self>, item: E) -> Result<()> { todo!() } fn poll_flush( self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { todo!() } fn poll_close( self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { todo!() } }