Namespaces fixes - deserializer (#10)

This commit is contained in:
choinskib 2022-08-25 13:16:19 +02:00 committed by GitHub
parent ba40445c5e
commit fcf20aa507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 440 additions and 121 deletions

View File

@ -1,7 +1,7 @@
use proc_macro2::{Ident, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::quote; use quote::quote;
use crate::{get_namespaces, retrieve_attr}; use crate::{get_namespaces, retrieve_field_attribute, FieldAttribute};
struct Tokens { struct Tokens {
enum_: TokenStream, enum_: TokenStream,
@ -37,8 +37,9 @@ impl Deserializer {
let name = ident.to_string(); let name = ident.to_string();
let mut out = TokenStream::new(); let mut out = TokenStream::new();
let (_, other_namespaces) = get_namespaces(&input.attrs); let (default_namespace, other_namespaces) = get_namespaces(&input.attrs);
let mut namespaces_map = quote!(let mut namespaces_map = std::collections::HashMap::new();); let mut namespaces_map = quote!(let mut namespaces_map = std::collections::HashMap::new(););
for (k, v) in other_namespaces.iter() { for (k, v) in other_namespaces.iter() {
namespaces_map.extend(quote!( namespaces_map.extend(quote!(
namespaces_map.insert(#k, #v); namespaces_map.insert(#k, #v);
@ -58,16 +59,26 @@ impl Deserializer {
match data.fields { match data.fields {
syn::Fields::Named(ref fields) => { syn::Fields::Named(ref fields) => {
fields.named.iter().enumerate().for_each(|(index, field)| { fields.named.iter().enumerate().for_each(|(index, field)| {
let is_element; let mut field_namespace = None;
let tokens = match retrieve_attr("attribute", &field.attrs) { let (tokens, def_prefix, is_element) = match retrieve_field_attribute(field) {
Some(true) => { Some(FieldAttribute::Namespace(value)) => {
is_element = false; field_namespace = Some(value);
&mut attributes_tokens (&mut elements_tokens, None, true)
} }
_ => { Some(FieldAttribute::PrefixIdentifier(def_prefix)) => {
is_element = true; if other_namespaces.get(&def_prefix).is_none() {
&mut elements_tokens panic!("Namespace with such prefix do not exist for this struct");
} }
(&mut elements_tokens, Some(def_prefix), true)
},
Some(FieldAttribute::Attribute) => {
(&mut attributes_tokens, None, false)
}
None => {
(&mut elements_tokens, None, true)
},
}; };
Self::process_field( Self::process_field(
@ -77,10 +88,12 @@ impl Deserializer {
&mut return_val, &mut return_val,
tokens, tokens,
is_element, is_element,
def_prefix,
field_namespace,
); );
}); });
} }
syn::Fields::Unnamed(_) => todo!(), syn::Fields::Unnamed(_) => panic!("unamed"),
syn::Fields::Unit => {} syn::Fields::Unit => {}
}; };
} }
@ -137,7 +150,6 @@ impl Deserializer {
fn visit_struct<'a>(&self, deserializer: &mut ::instant_xml::Deserializer) -> Result<Self::Value, ::instant_xml::Error> fn visit_struct<'a>(&self, deserializer: &mut ::instant_xml::Deserializer) -> Result<Self::Value, ::instant_xml::Error>
{ {
#declare_values #declare_values
while let Some(( key, _ )) = deserializer.peek_next_attribute() { while let Some(( key, _ )) = deserializer.peek_next_attribute() {
match get_attribute(&key) { match get_attribute(&key) {
#attr_type_match #attr_type_match
@ -149,10 +161,11 @@ impl Deserializer {
XmlRecord::Open(item) => { XmlRecord::Open(item) => {
match get_element(&item.key.as_ref()) { match get_element(&item.key.as_ref()) {
#elem_type_match #elem_type_match
__Elements::__Ignore => todo!(), __Elements::__Ignore => panic!("No such element"),
} }
} }
XmlRecord::Close(tag) => { XmlRecord::Close(tag) => {
println!("Close: {}", tag);
if tag == &#name { if tag == &#name {
break; break;
} }
@ -168,7 +181,7 @@ impl Deserializer {
} }
#namespaces_map; #namespaces_map;
deserializer.deserialize_struct(StructVisitor{}, #name, &namespaces_map) deserializer.deserialize_struct(StructVisitor{}, #name, #default_namespace, &namespaces_map)
} }
)); ));
@ -179,6 +192,7 @@ impl Deserializer {
Deserializer { out } Deserializer { out }
} }
#[allow(clippy::too_many_arguments)]
fn process_field( fn process_field(
field: &syn::Field, field: &syn::Field,
index: usize, index: usize,
@ -186,13 +200,15 @@ impl Deserializer {
return_val: &mut TokenStream, return_val: &mut TokenStream,
tokens: &mut Tokens, tokens: &mut Tokens,
is_element: bool, is_element: bool,
def_prefix: Option<String>,
field_namespace: Option<String>,
) { ) {
let field_var = field.ident.as_ref().unwrap(); let field_var = field.ident.as_ref().unwrap();
let field_var_str = field_var.to_string(); let field_var_str = field_var.to_string();
let const_field_var_str = Ident::new(&field_var_str.to_uppercase(), Span::call_site()); let const_field_var_str = Ident::new(&field_var_str.to_uppercase(), Span::call_site());
let field_type = match &field.ty { let field_type = match &field.ty {
syn::Type::Path(v) => v.path.get_ident(), syn::Type::Path(v) => v.path.get_ident(),
_ => todo!(), _ => panic!("Wrong field attribute format"),
}; };
let enum_name = Ident::new(&format!("__Value{index}"), Span::call_site()); let enum_name = Ident::new(&format!("__Value{index}"), Span::call_site());
@ -219,6 +235,18 @@ impl Deserializer {
let mut #enum_name: Option<#field_type> = None; let mut #enum_name: Option<#field_type> = None;
)); ));
let def_prefix = match def_prefix {
Some(def_prefix) => quote!(let def_prefix: Option<&str> = Some(#def_prefix);),
None => quote!(let def_prefix: Option<&str> = None;),
};
let field_namespace = match field_namespace {
Some(field_namespace) => {
quote!(let field_namespace: Option<&str> = Some(#field_namespace);)
}
None => quote!(let field_namespace: Option<&str> = None;),
};
if is_element { if is_element {
tokens.match_.extend(quote!( tokens.match_.extend(quote!(
__Elements::#enum_name => { __Elements::#enum_name => {
@ -226,11 +254,35 @@ impl Deserializer {
panic!("duplicated value"); panic!("duplicated value");
} }
if let Some(item) = item.prefix { match item.prefix {
let prefix = item.to_owned(); Some(item) => {
deserializer.verify_namespace(&prefix); let parser_prefix = item.to_owned();
#def_prefix
match def_prefix {
Some(def_prefix) => {
// Check if defined and gotten namespaces equals for each field
if deserializer.get_parser_namespace(&parser_prefix)
!= deserializer.get_def_namespace(def_prefix) {
return Err(Error::WrongNamespace)
} }
}
None => {
return Err(Error::WrongNamespace);
}
}
}
None => {
#def_prefix
match def_prefix {
Some(_) => {
return Err(Error::WrongNamespace)
},
None => (),
}
}
}
#field_namespace
deserializer.set_next_def_namespace(field_namespace)?;
#enum_name = Some(#field_type::deserialize(deserializer)?); #enum_name = Some(#field_type::deserialize(deserializer)?);
}, },
)); ));

View File

@ -16,23 +16,25 @@ const XML: &str = "xml";
pub(crate) enum FieldAttribute { pub(crate) enum FieldAttribute {
Namespace(String), Namespace(String),
PrefixIdentifier(String), PrefixIdentifier(String),
Attribute,
} }
pub(crate) fn get_namespaces( pub(crate) fn get_namespaces(
attributes: &Vec<syn::Attribute>, attributes: &Vec<syn::Attribute>,
) -> (Option<String>, HashMap<String, String>) { ) -> (String, HashMap<String, String>) {
let mut default_namespace = None; let mut default_namespace = String::new();
let mut other_namespaces = HashMap::default(); let mut other_namespaces = HashMap::default();
let list = match retrieve_attr_list("namespace", attributes) { let (list, name) = match retrieve_attr_list(attributes) {
Some(v) => v, Some((Some(list), name)) => (list, name),
None => return (default_namespace, other_namespaces), None => return (default_namespace, other_namespaces),
_ => panic!("wrong parameters"),
}; };
if list.path.get_ident().unwrap() == "namespace" { if name == "namespace" {
let mut iter = list.nested.iter(); let mut iter = list.nested.iter();
if let Some(NestedMeta::Lit(Lit::Str(v))) = iter.next() { if let Some(NestedMeta::Lit(Lit::Str(v))) = iter.next() {
default_namespace = Some(v.value()); default_namespace = v.value();
} }
for item in iter { for item in iter {
@ -50,24 +52,26 @@ pub(crate) fn get_namespaces(
(default_namespace, other_namespaces) (default_namespace, other_namespaces)
} }
pub(crate) fn retrieve_field_attribute(name: &str, input: &syn::Field) -> Option<FieldAttribute> { pub(crate) fn retrieve_field_attribute(input: &syn::Field) -> Option<FieldAttribute> {
if let Some(list) = retrieve_attr_list(name, &input.attrs) { match retrieve_attr_list(&input.attrs) {
match list.nested.first() { Some((Some(list), name)) if name.as_str() == "namespace" => match list.nested.first() {
Some(NestedMeta::Lit(Lit::Str(v))) => { Some(NestedMeta::Lit(Lit::Str(v))) => Some(FieldAttribute::Namespace(v.value())),
return Some(FieldAttribute::Namespace(v.value()));
}
Some(NestedMeta::Meta(Meta::Path(v))) => { Some(NestedMeta::Meta(Meta::Path(v))) => {
if let Some(ident) = v.get_ident() { if let Some(ident) = v.get_ident() {
return Some(FieldAttribute::PrefixIdentifier(ident.to_string())); Some(FieldAttribute::PrefixIdentifier(ident.to_string()))
} else {
panic!("unexpected parameter");
} }
} }
_ => (), _ => panic!("unexpected parameter"),
}; },
Some((None, name)) if name.as_str() == "attribute" => Some(FieldAttribute::Attribute),
None => None,
_ => panic!("unexpected parameter"),
} }
None
} }
pub(crate) fn retrieve_attr(name: &str, attributes: &Vec<syn::Attribute>) -> Option<bool> { fn retrieve_attr_list(attributes: &Vec<syn::Attribute>) -> Option<(Option<syn::MetaList>, String)> {
for attr in attributes { for attr in attributes {
if !attr.path.is_ident(XML) { if !attr.path.is_ident(XML) {
continue; continue;
@ -75,41 +79,19 @@ pub(crate) fn retrieve_attr(name: &str, attributes: &Vec<syn::Attribute>) -> Opt
let nested = match attr.parse_meta() { let nested = match attr.parse_meta() {
Ok(Meta::List(meta)) => meta.nested, Ok(Meta::List(meta)) => meta.nested,
_ => return Some(false), Ok(_) => todo!(),
}; _ => todo!(),
let path = match nested.first() {
Some(NestedMeta::Meta(Meta::Path(path))) => path,
_ => return Some(false),
};
if path.get_ident()? == name {
return Some(true);
}
}
None
}
fn retrieve_attr_list(name: &str, attributes: &Vec<syn::Attribute>) -> Option<syn::MetaList> {
for attr in attributes {
if !attr.path.is_ident(XML) {
continue;
}
let nested = match attr.parse_meta() {
Ok(Meta::List(meta)) => meta.nested,
_ => return None,
}; };
let list = match nested.first() { let list = match nested.first() {
Some(NestedMeta::Meta(Meta::List(list))) => list, Some(NestedMeta::Meta(Meta::List(list))) => list,
Some(NestedMeta::Meta(Meta::Path(path))) => {
return Some((None, path.get_ident()?.to_string()))
}
_ => return None, _ => return None,
}; };
if list.path.get_ident()? == name { return Some((Some(list.to_owned()), list.path.get_ident()?.to_string()));
return Some(list.to_owned());
}
} }
None None
@ -158,7 +140,7 @@ pub fn to_xml(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// Check if prefix exist // Check if prefix exist
#( #(
if serializer.parent_prefixes.get(#missing_prefixes).is_none() { if serializer.parent_prefixes.get(#missing_prefixes).is_none() {
return Err(instant_xml::Error::UnexpectedPrefix); return Err(instant_xml::Error::WrongNamespace);
} }
)*; )*;

View File

@ -6,7 +6,7 @@ use quote::quote;
use crate::{get_namespaces, retrieve_field_attribute, FieldAttribute}; use crate::{get_namespaces, retrieve_field_attribute, FieldAttribute};
pub struct Serializer { pub struct Serializer {
default_namespace: Option<String>, default_namespace: String,
other_namespaces: HashMap<String, String>, other_namespaces: HashMap<String, String>,
} }
@ -33,7 +33,8 @@ impl<'a> Serializer {
serializer.output.write_str(field_context.name)?; serializer.output.write_str(field_context.name)?;
)); ));
if let Some(default_namespace) = self.default_namespace.as_ref() { if !self.default_namespace.is_empty() {
let default_namespace = &self.default_namespace;
output.extend(quote!( output.extend(quote!(
serializer.output.write_str(" xmlns=\"")?; serializer.output.write_str(" xmlns=\"")?;
serializer.output.write_str(#default_namespace)?; serializer.output.write_str(#default_namespace)?;
@ -82,7 +83,7 @@ impl<'a> Serializer {
}; };
)); ));
match retrieve_field_attribute("namespace", field) { match retrieve_field_attribute(field) {
Some(FieldAttribute::Namespace(namespace_key)) => { Some(FieldAttribute::Namespace(namespace_key)) => {
output.extend(quote!( output.extend(quote!(
field.attribute = Some(instant_xml::FieldAttribute::Namespace(#namespace_key)); field.attribute = Some(instant_xml::FieldAttribute::Namespace(#namespace_key));

View File

@ -14,11 +14,8 @@ pub mod parse;
pub struct TagData<'xml> { pub struct TagData<'xml> {
pub key: &'xml str, pub key: &'xml str,
pub attributes: Vec<(&'xml str, &'xml str)>, pub attributes: Vec<(&'xml str, &'xml str)>,
// TODO: handle default namespace
pub default_namespace: Option<&'xml str>, pub default_namespace: Option<&'xml str>,
pub namespaces: HashMap<&'xml str, &'xml str>,
pub namespaces: Option<HashMap<&'xml str, &'xml str>>,
pub prefix: Option<&'xml str>, pub prefix: Option<&'xml str>,
} }
@ -236,18 +233,26 @@ pub trait Visitor<'xml>: Sized {
pub struct Deserializer<'xml> { pub struct Deserializer<'xml> {
parser: XmlParser<'xml>, parser: XmlParser<'xml>,
namespaces: HashMap<&'xml str, &'xml str>, def_namespaces: HashMap<&'xml str, &'xml str>,
parser_namespaces: HashMap<&'xml str, &'xml str>,
def_defualt_namespace: &'xml str,
parser_defualt_namespace: &'xml str,
tag_attributes: Vec<(&'xml str, &'xml str)>, tag_attributes: Vec<(&'xml str, &'xml str)>,
next_type: EntityType, next_type: EntityType,
next_def_namespace: Option<&'xml str>,
} }
impl<'xml> Deserializer<'xml> { impl<'xml> Deserializer<'xml> {
pub fn new(input: &'xml str) -> Self { pub fn new(input: &'xml str) -> Self {
Self { Self {
parser: XmlParser::new(input), parser: XmlParser::new(input),
namespaces: std::collections::HashMap::new(), def_namespaces: std::collections::HashMap::new(),
parser_namespaces: std::collections::HashMap::new(),
def_defualt_namespace: "",
parser_defualt_namespace: "",
tag_attributes: Vec::new(), tag_attributes: Vec::new(),
next_type: EntityType::Element, next_type: EntityType::Element,
next_def_namespace: None,
} }
} }
@ -255,8 +260,16 @@ impl<'xml> Deserializer<'xml> {
self.parser.peek_next_tag() self.parser.peek_next_tag()
} }
pub fn verify_namespace(&self, namespace_to_verify: &str) -> bool { pub fn get_def_namespace(&self, prefix: &str) -> Option<&&str> {
self.namespaces.get(namespace_to_verify).is_some() self.def_namespaces.get(prefix)
}
pub fn get_parser_namespace(&self, prefix: &str) -> Option<&&str> {
self.parser_namespaces.get(prefix)
}
pub fn compare_parser_and_def_default_namespaces(&self) -> bool {
self.parser_defualt_namespace == self.def_defualt_namespace
} }
pub fn peek_next_attribute(&self) -> Option<&(&'xml str, &'xml str)> { pub fn peek_next_attribute(&self) -> Option<&(&'xml str, &'xml str)> {
@ -267,24 +280,79 @@ impl<'xml> Deserializer<'xml> {
&mut self, &mut self,
visitor: V, visitor: V,
name: &str, name: &str,
namespaces: &HashMap<&'xml str, &'xml str>, def_default_namespace: &'xml str,
def_namespaces: &HashMap<&'xml str, &'xml str>,
) -> Result<V::Value, Error> ) -> Result<V::Value, Error>
where where
V: Visitor<'xml>, V: Visitor<'xml>,
{ {
let new_namespaces = namespaces // Saveing current defined default namespace
let def_defualt_namespace_to_revert = self.def_defualt_namespace;
self.def_defualt_namespace = def_default_namespace;
// Adding struct defined namespaces
let new_def_namespaces = def_namespaces
.iter() .iter()
.filter(|(k, v)| self.namespaces.insert(k, v).is_none()) .filter(|(k, v)| self.def_namespaces.insert(k, v).is_none())
.collect::<Vec<_>>();
// Process open tag
let tag_data = match self.parser.next() {
Some(Ok(XmlRecord::Open(item))) if item.key == name => item,
_ => return Err(Error::UnexpectedValue),
};
// Set current attributes
self.tag_attributes = tag_data.attributes;
// Saveing current parser default namespace
let parser_defualt_namespace_to_revert = self.parser_defualt_namespace;
// Set parser default namespace
match tag_data.default_namespace {
Some(namespace) => {
self.parser_defualt_namespace = namespace;
}
None => {
// If there is no default namespace in the tag, check if parent default namespace equals the current one
if def_defualt_namespace_to_revert != self.def_defualt_namespace {
return Err(Error::WrongNamespace);
}
}
}
// Compare parser namespace with defined one
if !self.compare_parser_and_def_default_namespaces() {
return Err(Error::WrongNamespace);
}
// Adding parser namespaces
let new_parser_namespaces = tag_data
.namespaces
.iter()
.filter(|(k, v)| self.parser_namespaces.insert(k, v).is_none())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.process_open_tag(name, namespaces)?;
let ret = visitor.visit_struct(self)?; let ret = visitor.visit_struct(self)?;
// Process close tag
self.check_close_tag(name)?; self.check_close_tag(name)?;
let _ = new_namespaces
.iter()
.map(|(k, _)| self.namespaces.remove(*k));
// Removing parser namespaces
let _ = new_parser_namespaces
.iter()
.map(|(k, _)| self.parser_namespaces.remove(*k));
// Removing struct defined namespaces
let _ = new_def_namespaces
.iter()
.map(|(k, _)| self.def_namespaces.remove(*k));
// Retriving old defined namespace
self.def_defualt_namespace = def_defualt_namespace_to_revert;
// Retriving old parser namespace
self.parser_defualt_namespace = parser_defualt_namespace_to_revert;
Ok(ret) Ok(ret)
} }
@ -303,11 +371,35 @@ impl<'xml> Deserializer<'xml> {
ret ret
} }
pub fn set_next_def_namespace(&mut self, namespace: Option<&'xml str>) -> Result<(), Error> {
if self.next_def_namespace.is_some() {
return Err(Error::UnexpectedState);
}
self.next_def_namespace = namespace;
Ok(())
}
pub fn consume_next_def_namespace(&mut self) -> Option<&'xml str> {
let ret = self.next_def_namespace;
self.next_def_namespace = None;
ret
}
fn deserialize_bool<V>(&mut self, visitor: V) -> Result<V::Value, Error> fn deserialize_bool<V>(&mut self, visitor: V) -> Result<V::Value, Error>
where where
V: Visitor<'xml>, V: Visitor<'xml>,
{ {
self.parser.next(); // Process open tag
let tag_data = match self.parser.next() {
Some(Ok(XmlRecord::Open(item))) => item,
_ => return Err(Error::UnexpectedValue),
};
if tag_data.default_namespace != self.consume_next_def_namespace() {
return Err(Error::WrongNamespace);
}
match self.parser.next() { match self.parser.next() {
Some(Ok(XmlRecord::Element(v))) => { Some(Ok(XmlRecord::Element(v))) => {
let ret = visitor.visit_str(v); let ret = visitor.visit_str(v);
@ -328,28 +420,6 @@ impl<'xml> Deserializer<'xml> {
} }
} }
fn process_open_tag(
&mut self,
name: &str,
namespaces: &HashMap<&'xml str, &'xml str>,
) -> Result<(), Error> {
let item = match self.parser.next() {
Some(Ok(XmlRecord::Open(item))) if item.key == name => item,
_ => return Err(Error::UnexpectedValue),
};
for (k, v) in item.namespaces.unwrap() {
match namespaces.get(k) {
Some(item) if *item != v => return Err(Error::UnexpectedPrefix),
None => return Err(Error::MissingdPrefix),
_ => (),
}
}
self.tag_attributes = item.attributes;
Ok(())
}
fn check_close_tag(&mut self, name: &str) -> Result<(), Error> { fn check_close_tag(&mut self, name: &str) -> Result<(), Error> {
let item = match self.parser.next() { let item = match self.parser.next() {
Some(item) => item?, Some(item) => item?,
@ -370,7 +440,7 @@ struct State<'a> {
prefix: HashMap<&'a str, &'a str>, prefix: HashMap<&'a str, &'a str>,
} }
#[derive(Debug, Error)] #[derive(Debug, Error, PartialEq, Eq)]
pub enum Error { pub enum Error {
#[error("format: {0}")] #[error("format: {0}")]
Format(#[from] fmt::Error), Format(#[from] fmt::Error),
@ -392,8 +462,8 @@ pub enum Error {
UnexpectedToken, UnexpectedToken,
#[error("missing prefix")] #[error("missing prefix")]
MissingdPrefix, MissingdPrefix,
#[error("unexpected prefix")]
UnexpectedPrefix,
#[error("unexpected state")] #[error("unexpected state")]
UnexpectedState, UnexpectedState,
#[error("wrong namespace")]
WrongNamespace,
} }

View File

@ -35,8 +35,8 @@ impl<'a> XmlParser<'a> {
Ok(Some(XmlRecord::Open(TagData { Ok(Some(XmlRecord::Open(TagData {
key: local, key: local,
attributes: Vec::new(), attributes: Vec::new(),
default_namespace: None, default_namespace: Some(""),
namespaces: None, namespaces: HashMap::new(),
prefix, prefix,
}))) })))
} }
@ -89,7 +89,7 @@ impl<'xml> Iterator for XmlParser<'xml> {
key: key.unwrap(), key: key.unwrap(),
attributes, attributes,
default_namespace, default_namespace,
namespaces: Some(namespaces), namespaces,
prefix: prefix_ret, prefix: prefix_ret,
}))); })));
} }

View File

@ -1,6 +1,6 @@
use instant_xml::{FromXml, ToXml}; use instant_xml::{Error, FromXml, ToXml};
#[derive(Debug, Eq, PartialEq, ToXml, FromXml)] #[derive(Debug, Eq, PartialEq, ToXml)]
struct Nested { struct Nested {
#[xml(namespace(bar))] #[xml(namespace(bar))]
flag: bool, flag: bool,
@ -66,6 +66,13 @@ fn struct_with_custom_field() {
); );
} }
#[derive(Debug, Eq, PartialEq, ToXml, FromXml)]
#[xml(namespace("URI", bar = "BAZ"))]
struct NestedDe {
#[xml(namespace(bar))]
flag: bool,
}
#[derive(Debug, Eq, PartialEq, ToXml)] #[derive(Debug, Eq, PartialEq, ToXml)]
#[xml(namespace("URI", bar = "BAZ", foo = "BAR"))] #[xml(namespace("URI", bar = "BAZ", foo = "BAR"))]
struct StructWithCustomFieldWrongPrefix { struct StructWithCustomFieldWrongPrefix {
@ -89,31 +96,238 @@ struct StructWithCustomFieldFromXml {
flag: bool, flag: bool,
#[xml(attribute)] #[xml(attribute)]
flag_attribute: bool, flag_attribute: bool,
test: Nested, test: NestedDe,
} }
#[test] #[test]
fn struct_with_custom_field_from_xml() { fn struct_with_custom_field_from_xml() {
assert_eq!( assert_eq!(
StructWithCustomFieldFromXml::from_xml("<StructWithCustomFieldFromXml flag_attribute=\"true\" xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\"><bar:flag>false</bar:flag><Nested><flag>true</flag></Nested></StructWithCustomFieldFromXml>").unwrap(), StructWithCustomFieldFromXml::from_xml("<StructWithCustomFieldFromXml flag_attribute=\"true\" xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\"><bar:flag>false</bar:flag><NestedDe><bar:flag>true</bar:flag></NestedDe></StructWithCustomFieldFromXml>").unwrap(),
StructWithCustomFieldFromXml { StructWithCustomFieldFromXml {
flag: false, flag: false,
flag_attribute: true, flag_attribute: true,
test: Nested { flag: true } test: NestedDe { flag: true }
} }
); );
// Different order // Different order
assert_eq!( assert_eq!(
StructWithCustomFieldFromXml::from_xml("<StructWithCustomFieldFromXml xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\" flag_attribute=\"true\"><Nested><flag>true</flag></Nested><flag>false</flag></StructWithCustomFieldFromXml>").unwrap(), StructWithCustomFieldFromXml::from_xml("<StructWithCustomFieldFromXml xmlns=\"URI\" xmlns:bar=\"BAZ\" xmlns:foo=\"BAR\" flag_attribute=\"true\"><NestedDe><bar:flag>true</bar:flag></NestedDe><bar:flag>false</bar:flag></StructWithCustomFieldFromXml>").unwrap(),
StructWithCustomFieldFromXml { StructWithCustomFieldFromXml {
flag: false, flag: false,
flag_attribute: true, flag_attribute: true,
test: Nested { flag: true } test: NestedDe { flag: true }
}
);
// Different prefixes then in definition
assert_eq!(
StructWithCustomFieldFromXml::from_xml("<StructWithCustomFieldFromXml flag_attribute=\"true\" xmlns=\"URI\" xmlns:grr=\"BAZ\" xmlns:foo=\"BAR\"><grr:flag>false</grr:flag><NestedDe><grr:flag>true</grr:flag></NestedDe></StructWithCustomFieldFromXml>").unwrap(),
StructWithCustomFieldFromXml {
flag: false,
flag_attribute: true,
test: NestedDe { flag: true }
} }
); );
assert_eq!( assert_eq!(
Nested::from_xml("<Nested><flag>true</flag></Nested>").unwrap(), NestedDe::from_xml(
Nested { flag: true } "<NestedDe xmlns=\"URI\" xmlns:bar=\"BAZ\"><bar:flag>true</bar:flag></NestedDe>"
)
.unwrap(),
NestedDe { flag: true }
);
}
#[derive(Debug, Eq, PartialEq, ToXml, FromXml)]
struct NestedWrongNamespace {
flag: bool,
}
#[derive(Debug, Eq, PartialEq, FromXml)]
#[xml(namespace("URI", bar = "BAZ"))]
struct StructWithCorrectNestedNamespace {
test: NestedDe,
}
#[derive(Debug, Eq, PartialEq, FromXml)]
#[xml(namespace("URI", bar = "BAZ"))]
struct StructWithWrongNestedNamespace {
test: NestedWrongNamespace,
}
#[test]
fn default_namespaces() {
// Default namespace not-nested
assert_eq!(
NestedDe::from_xml(
"<NestedDe xmlns=\"URI\" xmlns:bar=\"BAZ\"><bar:flag>true</bar:flag></NestedDe>"
)
.unwrap(),
NestedDe { flag: true }
);
// Default namespace not-nested - wrong namespace
assert_eq!(
NestedDe::from_xml(
"<NestedDe xmlns=\"WRONG\" xmlns:bar=\"BAZ\"><bar:flag>true</bar:flag></NestedDe>"
)
.unwrap_err(),
Error::WrongNamespace
);
// Correct child namespace
assert_eq!(
StructWithCorrectNestedNamespace::from_xml("<StructWithCorrectNestedNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><NestedDe xmlns=\"URI\" xmlns:bar=\"BAZ\"><bar:flag>true</bar:flag></NestedDe></StructWithCorrectNestedNamespace>").unwrap(),
StructWithCorrectNestedNamespace {
test: NestedDe { flag: true }
}
);
// Correct child namespace - without child redefinition
assert_eq!(
StructWithCorrectNestedNamespace::from_xml("<StructWithCorrectNestedNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><NestedDe><bar:flag>true</bar:flag></NestedDe></StructWithCorrectNestedNamespace>").unwrap(),
StructWithCorrectNestedNamespace {
test: NestedDe { flag: true }
}
);
// Different child namespace
assert_eq!(
StructWithWrongNestedNamespace::from_xml("<StructWithWrongNestedNamespace xmlns=\"URI\" xmlns:dar=\"BAZ\"><NestedWrongNamespace xmlns=\"\"><flag>true</flag></NestedWrongNamespace></StructWithWrongNestedNamespace>").unwrap(),
StructWithWrongNestedNamespace {
test: NestedWrongNamespace {
flag: true
}
}
);
// Wrong child namespace
assert_eq!(
StructWithWrongNestedNamespace::from_xml("<StructWithWrongNestedNamespace xmlns=\"URI\" xmlns:dar=\"BAZ\"><NestedWrongNamespace><flag>true</flag></NestedWrongNamespace></StructWithWrongNestedNamespace>").unwrap_err(),
Error::WrongNamespace
);
}
#[derive(Debug, Eq, PartialEq, FromXml)]
#[xml(namespace("URI", bar = "BAZ"))]
struct NestedOtherNamespace {
#[xml(namespace(bar))]
flag: bool,
}
#[derive(Debug, Eq, PartialEq, FromXml)]
#[xml(namespace("URI", bar = "BAZ"))]
struct StructOtherNamespace {
test: NestedOtherNamespace,
}
#[test]
fn other_namespaces() {
// Other namespace not-nested
assert_eq!(
NestedOtherNamespace::from_xml(
"<NestedOtherNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><bar:flag>true</bar:flag></NestedOtherNamespace>"
)
.unwrap(),
NestedOtherNamespace { flag: true }
);
// Other namespace not-nested - wrong defined namespace
assert_eq!(
NestedOtherNamespace::from_xml(
"<NestedOtherNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><wrong:flag>true</wrong:flag></NestedOtherNamespace>"
)
.unwrap_err(),
Error::WrongNamespace
);
// Other namespace not-nested - wrong parser namespace
assert_eq!(
NestedOtherNamespace::from_xml(
"<NestedOtherNamespace xmlns=\"URI\" xmlns:bar=\"WRONG\"><bar:flag>true</bar:flag></NestedOtherNamespace>"
)
.unwrap_err(),
Error::WrongNamespace
);
// Other namespace not-nested - missing parser prefix
assert_eq!(
NestedOtherNamespace::from_xml(
"<NestedOtherNamespace xmlns=\"URI\" xmlns:bar=\"BAR\"><flag>true</flag></NestedOtherNamespace>"
)
.unwrap_err(),
Error::WrongNamespace
);
// Correct child other namespace
assert_eq!(
StructOtherNamespace::from_xml(
"<StructOtherNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><NestedOtherNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><bar:flag>true</bar:flag></NestedOtherNamespace></StructOtherNamespace>"
)
.unwrap(),
StructOtherNamespace {
test: NestedOtherNamespace {
flag: true,
}
}
);
// Correct child other namespace - without child redefinition
assert_eq!(
StructOtherNamespace::from_xml(
"<StructOtherNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><NestedOtherNamespace><bar:flag>true</bar:flag></NestedOtherNamespace></StructOtherNamespace>"
)
.unwrap(),
StructOtherNamespace {
test: NestedOtherNamespace {
flag: true,
}
}
);
// Wrong child other namespace - without child redefinition
assert_eq!(
StructOtherNamespace::from_xml(
"<StructOtherNamespace xmlns=\"URI\" xmlns:bar=\"BAZ\"><NestedOtherNamespace><wrong:flag>true</wrong:flag></NestedOtherNamespace></StructOtherNamespace>"
)
.unwrap_err(),
Error::WrongNamespace
);
}
#[derive(Debug, Eq, PartialEq, FromXml)]
#[xml(namespace("URI"))]
struct StructDirectNamespace {
#[xml(namespace("BAZ"))]
flag: bool,
}
#[test]
fn direct_namespaces() {
// Correct direct namespace
assert_eq!(
StructDirectNamespace::from_xml(
"<StructDirectNamespace xmlns=\"URI\"><flag xmlns=\"BAZ\">true</flag></StructDirectNamespace>"
)
.unwrap(),
StructDirectNamespace { flag: true }
);
// Wrong direct namespace
assert_eq!(
StructDirectNamespace::from_xml(
"<StructDirectNamespace xmlns=\"URI\"><flag xmlns=\"WRONG\">true</flag></StructDirectNamespace>"
)
.unwrap_err(),
Error::WrongNamespace
);
// Wrong direct namespace - missing namespace
assert_eq!(
StructDirectNamespace::from_xml(
"<StructDirectNamespace xmlns=\"URI\"><flag>true</flag></StructDirectNamespace>"
)
.unwrap_err(),
Error::WrongNamespace
); );
} }