use quick_xml::events::Event; use quick_xml::name::ResolveResult; use rustical_xml::NamespaceOwned; use rustical_xml::Unparsed; use rustical_xml::XmlDeserialize; use rustical_xml::XmlError; use rustical_xml::XmlRootTag; #[derive(Debug, Clone, XmlDeserialize, XmlRootTag, PartialEq)] #[xml(root = b"propfind", ns = "crate::namespace::NS_DAV")] pub struct PropfindElement { #[xml(ty = "untagged")] pub prop: PropfindType, } #[derive(Debug, Clone, PartialEq)] // pub struct PropElement(#[xml(ty = "untagged", flatten)] pub Vec); pub struct PropElement( // valid pub Vec, // invalid pub Vec<(Option, String)>, ); impl XmlDeserialize for PropElement { fn deserialize( reader: &mut quick_xml::NsReader, start: &quick_xml::events::BytesStart, empty: bool, ) -> Result { if empty { return Ok(Self(vec![], vec![])); } let mut buf = Vec::new(); let mut valid_props = vec![]; let mut invalid_props = vec![]; loop { let event = reader.read_event_into(&mut buf)?; match &event { Event::End(e) if e.name() == start.name() => { break; } Event::Eof => return Err(XmlError::Eof), // start of a child element Event::Start(start) | Event::Empty(start) => { let empty = matches!(event, Event::Empty(_)); let (ns, name) = reader.resolve_element(start.name()); let ns = match ns { ResolveResult::Bound(ns) => Some(NamespaceOwned::from(ns)), ResolveResult::Unknown(_ns) => todo!("handle error"), ResolveResult::Unbound => None, }; match PN::deserialize(reader, start, empty) { Ok(propname) => valid_props.push(propname), Err(XmlError::InvalidVariant(_)) => { invalid_props .push((ns, String::from_utf8_lossy(name.as_ref()).to_string())); // Consume content Unparsed::deserialize(reader, start, empty)?; } Err(err) => return Err(err), } } Event::Text(_) | Event::CData(_) => { return Err(XmlError::UnsupportedEvent("Not expecting text here")); } Event::Decl(_) | Event::Comment(_) | Event::DocType(_) | Event::PI(_) => { /* ignore */ } Event::End(_end) => { unreachable!( "Unexpected closing tag for wrong element, should be handled by quick_xml" ); } } } Ok(Self(valid_props, invalid_props)) } } #[derive(Debug, Clone, XmlDeserialize, PartialEq)] pub enum PropfindType { #[xml(ns = "crate::namespace::NS_DAV")] Propname, #[xml(ns = "crate::namespace::NS_DAV")] Allprop, #[xml(ns = "crate::namespace::NS_DAV")] Prop(PropElement), }