Introduce Node layer to gain full access to parsed element
This commit is contained in:
parent
611db8335e
commit
f42f9fd811
|
@ -35,8 +35,8 @@ impl Deserializer {
|
||||||
pub fn new(input: &syn::DeriveInput) -> Deserializer {
|
pub fn new(input: &syn::DeriveInput) -> Deserializer {
|
||||||
let ident = &input.ident;
|
let ident = &input.ident;
|
||||||
let container_meta = ContainerMeta::from_derive(input);
|
let container_meta = ContainerMeta::from_derive(input);
|
||||||
let default_namespace = match container_meta.ns.default {
|
let default_namespace = match &container_meta.ns.default {
|
||||||
Namespace::Default => String::new(),
|
Namespace::Default => "",
|
||||||
Namespace::Prefix(_) => panic!("container namespace cannot be prefix"),
|
Namespace::Prefix(_) => panic!("container namespace cannot be prefix"),
|
||||||
Namespace::Literal(ns) => ns,
|
Namespace::Literal(ns) => ns,
|
||||||
};
|
};
|
||||||
|
@ -103,6 +103,7 @@ impl Deserializer {
|
||||||
&mut return_val,
|
&mut return_val,
|
||||||
tokens,
|
tokens,
|
||||||
field_meta,
|
field_meta,
|
||||||
|
&container_meta,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -152,6 +153,8 @@ impl Deserializer {
|
||||||
&self,
|
&self,
|
||||||
deserializer: &mut ::instant_xml::Deserializer<'xml>
|
deserializer: &mut ::instant_xml::Deserializer<'xml>
|
||||||
) -> Result<Self::Value, ::instant_xml::Error> {
|
) -> Result<Self::Value, ::instant_xml::Error> {
|
||||||
|
use ::instant_xml::de::Node;
|
||||||
|
|
||||||
#declare_values
|
#declare_values
|
||||||
while let Some(( key, _ )) = deserializer.peek_next_attribute() {
|
while let Some(( key, _ )) = deserializer.peek_next_attribute() {
|
||||||
let attr = {
|
let attr = {
|
||||||
|
@ -167,12 +170,13 @@ impl Deserializer {
|
||||||
__Attributes::__Ignore => todo!(),
|
__Attributes::__Ignore => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while let Some(item) = &deserializer.peek_next_tag()? {
|
|
||||||
match item {
|
while let Some(node) = deserializer.peek_next_tag()? {
|
||||||
XmlRecord::Open(item) => {
|
match node {
|
||||||
|
Node::Open { ns, name } => {
|
||||||
let element = {
|
let element = {
|
||||||
#elements_consts
|
#elements_consts
|
||||||
match item.key.as_ref() {
|
match name {
|
||||||
#elements_names
|
#elements_names
|
||||||
_ => __Elements::__Ignore
|
_ => __Elements::__Ignore
|
||||||
}
|
}
|
||||||
|
@ -182,13 +186,13 @@ impl Deserializer {
|
||||||
#elem_type_match
|
#elem_type_match
|
||||||
__Elements::__Ignore => panic!("No such element"),
|
__Elements::__Ignore => panic!("No such element"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XmlRecord::Close(tag) => {
|
Node::Close { name } => {
|
||||||
if tag == &#name {
|
if name == #name {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
XmlRecord::Element(_) => panic!("Unexpected element"),
|
Node::Text { text } => panic!("Unexpected element"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +236,7 @@ impl Deserializer {
|
||||||
return_val: &mut TokenStream,
|
return_val: &mut TokenStream,
|
||||||
tokens: &mut Tokens,
|
tokens: &mut Tokens,
|
||||||
field_meta: FieldMeta,
|
field_meta: FieldMeta,
|
||||||
|
container_meta: &ContainerMeta,
|
||||||
) {
|
) {
|
||||||
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();
|
||||||
|
@ -260,10 +265,18 @@ impl Deserializer {
|
||||||
let mut #enum_name: Option<#no_lifetime_type> = None;
|
let mut #enum_name: Option<#no_lifetime_type> = None;
|
||||||
));
|
));
|
||||||
|
|
||||||
let (field_prefix, new_default_ns) = match field_meta.ns.default {
|
let default_ns = match field_meta.ns.default {
|
||||||
Namespace::Default => (quote!(None::<&str>), quote!(None::<&str>)),
|
Namespace::Default => &container_meta.ns.default,
|
||||||
Namespace::Prefix(prefix) => (quote!(Some(#prefix)), quote!(None)),
|
_ => &field_meta.ns.default,
|
||||||
Namespace::Literal(ns) => (quote!(None::<&str>), quote!(Some(#ns))),
|
};
|
||||||
|
|
||||||
|
let new_default_ns = match default_ns {
|
||||||
|
Namespace::Default => quote!(None),
|
||||||
|
Namespace::Prefix(prefix) => match container_meta.ns.prefixes.get(prefix) {
|
||||||
|
Some(ns) => quote!(Some(#ns)),
|
||||||
|
None => panic!("invalid prefix for xml attribute"),
|
||||||
|
},
|
||||||
|
Namespace::Literal(ns) => quote!(Some(#ns)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if !field_meta.attribute {
|
if !field_meta.attribute {
|
||||||
|
@ -273,8 +286,10 @@ impl Deserializer {
|
||||||
panic!("duplicated value");
|
panic!("duplicated value");
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializer.compare_namespace(&item.prefix, #field_prefix)?;
|
if Some(ns) != #new_default_ns {
|
||||||
deserializer.set_next_def_namespace(#new_default_ns)?;
|
return Err(Error::WrongNamespace);
|
||||||
|
}
|
||||||
|
|
||||||
#enum_name = Some(<#no_lifetime_type>::deserialize(deserializer)?);
|
#enum_name = Some(<#no_lifetime_type>::deserialize(deserializer)?);
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
|
@ -5,32 +5,53 @@ use super::Error;
|
||||||
use xmlparser::{ElementEnd, Token, Tokenizer};
|
use xmlparser::{ElementEnd, Token, Tokenizer};
|
||||||
|
|
||||||
pub struct Deserializer<'xml> {
|
pub struct Deserializer<'xml> {
|
||||||
parser: XmlParser<'xml>,
|
parser: Peekable<XmlParser<'xml>>,
|
||||||
def_namespaces: HashMap<&'xml str, &'xml str>,
|
def_namespaces: HashMap<&'xml str, &'xml str>,
|
||||||
parser_namespaces: HashMap<&'xml str, &'xml str>,
|
parser_namespaces: HashMap<&'xml str, &'xml str>,
|
||||||
def_default_namespace: &'xml str,
|
def_default_namespace: &'xml str,
|
||||||
parser_default_namespace: &'xml str,
|
parser_default_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).peekable(),
|
||||||
def_namespaces: std::collections::HashMap::new(),
|
def_namespaces: std::collections::HashMap::new(),
|
||||||
parser_namespaces: std::collections::HashMap::new(),
|
parser_namespaces: std::collections::HashMap::new(),
|
||||||
def_default_namespace: "",
|
def_default_namespace: "",
|
||||||
parser_default_namespace: "",
|
parser_default_namespace: "",
|
||||||
tag_attributes: Vec::new(),
|
tag_attributes: Vec::new(),
|
||||||
next_type: EntityType::Element,
|
next_type: EntityType::Element,
|
||||||
next_def_namespace: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_next_tag(&mut self) -> Result<Option<XmlRecord<'xml>>, Error> {
|
pub fn peek_next_tag(&mut self) -> Result<Option<Node<'xml>>, Error> {
|
||||||
self.parser.peek_next_tag()
|
let record = match self.parser.peek() {
|
||||||
|
Some(Ok(record)) => record,
|
||||||
|
Some(Err(err)) => return Err(err.clone()),
|
||||||
|
None => return Ok(None),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(match record {
|
||||||
|
XmlRecord::Open(TagData {
|
||||||
|
key, ns, prefix, ..
|
||||||
|
}) => {
|
||||||
|
let ns = match (ns, prefix) {
|
||||||
|
(_, Some(prefix)) => match self.parser_namespaces.get(prefix) {
|
||||||
|
Some(ns) => ns,
|
||||||
|
None => return Err(Error::WrongNamespace),
|
||||||
|
},
|
||||||
|
(Some(ns), None) => ns,
|
||||||
|
(None, None) => self.parser_default_namespace,
|
||||||
|
};
|
||||||
|
|
||||||
|
Node::Open { ns, name: key }
|
||||||
|
}
|
||||||
|
XmlRecord::Element(text) => Node::Text { text },
|
||||||
|
XmlRecord::Close(name) => Node::Close { name },
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if defined and gotten namespaces equals for each field
|
// Check if defined and gotten namespaces equals for each field
|
||||||
|
@ -158,30 +179,16 @@ 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(crate) fn deserialize_element<V>(&mut self, visitor: V) -> Result<V::Value, Error>
|
pub(crate) fn deserialize_element<V>(&mut self, visitor: V) -> Result<V::Value, Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'xml>,
|
V: Visitor<'xml>,
|
||||||
{
|
{
|
||||||
// Process open tag
|
// Process open tag
|
||||||
let tag_data = match self.parser.next() {
|
match self.parser.next() {
|
||||||
Some(Ok(XmlRecord::Open(item))) => item,
|
Some(Ok(XmlRecord::Open(_))) => {}
|
||||||
_ => return Err(Error::UnexpectedValue),
|
_ => return Err(Error::UnexpectedValue),
|
||||||
};
|
};
|
||||||
|
|
||||||
if tag_data.ns != self.next_def_namespace {
|
|
||||||
return Err(Error::WrongNamespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.next_def_namespace = None;
|
|
||||||
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);
|
||||||
|
@ -356,6 +363,12 @@ pub struct TagData<'xml> {
|
||||||
pub prefix: Option<&'xml str>,
|
pub prefix: Option<&'xml str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Node<'xml> {
|
||||||
|
Open { ns: &'xml str, name: &'xml str },
|
||||||
|
Close { name: &'xml str },
|
||||||
|
Text { text: &'xml str },
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub enum EntityType {
|
pub enum EntityType {
|
||||||
Element,
|
Element,
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl Kind {
|
||||||
|
|
||||||
pub trait FromXmlOwned: for<'xml> FromXml<'xml> {}
|
pub trait FromXmlOwned: for<'xml> FromXml<'xml> {}
|
||||||
|
|
||||||
#[derive(Debug, Error, PartialEq, Eq)]
|
#[derive(Clone, Debug, Eq, Error, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("format: {0}")]
|
#[error("format: {0}")]
|
||||||
Format(#[from] fmt::Error),
|
Format(#[from] fmt::Error),
|
||||||
|
|
Loading…
Reference in New Issue