diff --git a/crates/xml/derive/src/de/attrs.rs b/crates/xml/derive/src/de/attrs.rs index 5c86d77..86f2147 100644 --- a/crates/xml/derive/src/de/attrs.rs +++ b/crates/xml/derive/src/de/attrs.rs @@ -36,6 +36,7 @@ pub struct StructAttrs { pub container: ContainerAttrs, pub root: Option, + pub ns: Option, pub allow_invalid: Flag, } diff --git a/crates/xml/derive/src/de/de_struct.rs b/crates/xml/derive/src/de/de_struct.rs index 7abd0da..223b751 100644 --- a/crates/xml/derive/src/de/de_struct.rs +++ b/crates/xml/derive/src/de/de_struct.rs @@ -51,9 +51,14 @@ impl NamedStruct { let (impl_generics, type_generics, where_clause) = self.generics.split_for_impl(); let ident = &self.ident; let root = self.attrs.root.as_ref().expect("No root attribute found"); + let ns = match &self.attrs.ns { + Some(ns) => quote! { Some(#ns) }, + None => quote! { None }, + }; quote! { impl #impl_generics ::rustical_xml::XmlRoot for #ident #type_generics #where_clause { fn root_tag() -> &'static [u8] { #root } + fn root_ns() -> Option<&'static [u8]> { #ns } } } } diff --git a/crates/xml/src/de.rs b/crates/xml/src/de.rs index bc801f9..e5d2846 100644 --- a/crates/xml/src/de.rs +++ b/crates/xml/src/de.rs @@ -1,3 +1,5 @@ +use quick_xml::name::Namespace; +use quick_xml::name::ResolveResult; use std::io::BufRead; pub use xml_derive::XmlDeserialize; pub use xml_derive::XmlRoot; @@ -15,8 +17,8 @@ pub enum XmlDeError { QuickXmlAttrError(#[from] quick_xml::events::attributes::AttrError), #[error("Unknown error")] UnknownError, - #[error("Invalid tag {0}. Expected {1}")] - InvalidTag(String, String), + #[error("Invalid tag [{0}]{1}. Expected [{2}]{3}")] + InvalidTag(String, String, String, String), #[error("Missing field {0}")] MissingField(&'static str), #[error("End of file, expected closing tags")] @@ -51,16 +53,26 @@ pub trait XmlRoot { let empty = event.is_empty(); match event { Event::Start(start) | Event::Empty(start) => { - let (_ns, name) = reader.resolve_element(start.name()); - if name.as_ref() != Self::root_tag() { + let (ns, name) = reader.resolve_element(start.name()); + let matches = match (Self::root_ns(), &ns, name) { + // Wrong tag + (_, _, name) if name.as_ref() != Self::root_tag() => false, + // Wrong namespace + (Some(root_ns), ns, _) if &ResolveResult::Bound(Namespace(root_ns)) != ns => { + false + } + _ => true, + }; + if !matches { + let root_ns = Self::root_ns(); return Err(XmlDeError::InvalidTag( + format!("{ns:?}"), String::from_utf8_lossy(name.as_ref()).to_string(), + format!("{root_ns:?}"), String::from_utf8_lossy(Self::root_tag()).to_string(), )); }; - // TODO: check namespace - return Self::deserialize(&mut reader, &start, empty); } _ => {} @@ -78,6 +90,7 @@ pub trait XmlRoot { } fn root_tag() -> &'static [u8]; + fn root_ns() -> Option<&'static [u8]>; } pub trait XmlRootParseStr<'i>: XmlRoot + XmlDeserialize {