Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extension group support #33

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions xml_schema_derive/src/xsd/extension.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::xsd::{
attribute::Attribute, rust_types_mapping::RustTypesMapping, sequence::Sequence, Implementation,
XsdContext,
attribute::Attribute, group::Group, rust_types_mapping::RustTypesMapping, sequence::Sequence,
Implementation, XsdContext,
};
use proc_macro2::TokenStream;

Expand All @@ -17,6 +17,8 @@ pub struct Extension {
pub attributes: Vec<Attribute>,
#[yaserde(rename = "sequence")]
pub sequences: Vec<Sequence>,
#[yaserde(rename = "group")]
pub group: Option<Group>,
}

impl Implementation for Extension {
Expand All @@ -34,15 +36,15 @@ impl Implementation for Extension {
.map(|attribute| attribute.implement(namespace_definition, prefix, context))
.collect();

let inner_attribute = if format!("{rust_type}") == "String" {
let inner_attribute = if format!("{rust_type}") == "String" {
quote!(#[yaserde(text)])
} else {
TokenStream::new()
};

quote!(
#inner_attribute
pub content: #rust_type,
pub base: #rust_type,
#attributes
)
}
Expand All @@ -52,10 +54,28 @@ impl Extension {
pub fn get_field_implementation(
&self,
context: &XsdContext,
_prefix: &Option<String>,
prefix: &Option<String>,
) -> TokenStream {
let rust_type = RustTypesMapping::get(context, &self.base);
quote!(pub content : #rust_type)

let group_content = self
.group
.as_ref()
.map(|group| {
let group_type = group.get_type_implementation(context, prefix);

quote!(
,
#[serde(flatten)]
pub extension : #group_type
)
})
.unwrap_or_default();

quote!(
pub base : #rust_type
#group_content
)
}
}

Expand All @@ -70,6 +90,7 @@ mod tests {
base: "xs:string".to_string(),
attributes: vec![],
sequences: vec![],
group: None,
};

let context =
Expand Down Expand Up @@ -112,6 +133,7 @@ mod tests {
},
],
sequences: vec![],
group: None,
};

let context =
Expand Down
108 changes: 108 additions & 0 deletions xml_schema_derive/src/xsd/group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use crate::xsd::{
rust_types_mapping::RustTypesMapping, sequence::Sequence, Implementation, XsdContext,
};
use heck::ToUpperCamelCase;
use proc_macro2::{Span, TokenStream};
use syn::Ident;

#[derive(Clone, Default, Debug, PartialEq, YaDeserialize)]
#[yaserde(prefix = "xs", namespace = "xs: http://www.w3.org/2001/XMLSchema")]
pub struct Group {
#[yaserde(attribute)]
pub name: Option<String>,
#[yaserde(attribute, rename = "ref")]
pub reference: Option<String>,
#[yaserde()]
pub sequence: Option<Sequence>,
}

impl Implementation for Group {
fn implement(
&self,
namespace_definition: &TokenStream,
prefix: &Option<String>,
context: &XsdContext,
) -> TokenStream {
if self.name.is_none() {
return quote!();
}
let raw_name = self.name.clone().unwrap();

let struct_name = Ident::new(&raw_name.to_upper_camel_case(), Span::call_site());

let fields = self
.sequence
.as_ref()
.map(|sequence| sequence.get_field_implementation(context, prefix))
.unwrap_or_default();

quote!(
#[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
#namespace_definition
pub struct #struct_name {
#fields
}
)
}
}

impl Group {
pub fn get_type_implementation(
&self,
context: &XsdContext,
_prefix: &Option<String>,
) -> TokenStream {
if let Some(reference) = &self.reference {
RustTypesMapping::get(context, reference)
} else {
panic!("Missing reference for group");
}
}
}

#[cfg(test)]
mod tests {
use super::*;

use yaserde::de::from_str;

#[test]
fn check_group_implementation() {
let xml = r#"
<group name="groupthing">
<sequence>
<element name="CX_X" type="asdfg"/>
<element name="CY_X" type="asdfg"/>
</sequence>
</group>
"#;

let group: Group = from_str(xml).unwrap();

let context =
XsdContext::new(r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"></xs:schema>"#)
.unwrap();

let implementation = format!("{}", group.implement(&TokenStream::new(), &None, &context));

assert_eq!(implementation, "# [derive (Clone , Debug , Default , PartialEq , serde :: Deserialize , serde :: Serialize)] \
pub struct Groupthing { \
# [yaserde (rename = \"CX_X\")] pub cx_x : xml_schema_types :: Asdfg , \
# [yaserde (rename = \"CY_X\")] pub cy_x : xml_schema_types :: Asdfg , }");
}

#[test]
fn check_group_ref() {
let xml = r#"<group ref="bla:groupthing" />"#;

let group: Group = from_str(xml).unwrap();

let context =
XsdContext::new(r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"></xs:schema>"#)
.unwrap();

let type_implementation = format!("{}", group.get_type_implementation(&context, &None));

assert_eq!(type_implementation, "Groupthing");
}
}
1 change: 1 addition & 0 deletions xml_schema_derive/src/xsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod complex_content;
mod complex_type;
mod element;
mod extension;
mod group;
mod import;
mod list;
mod max_occurences;
Expand Down
19 changes: 17 additions & 2 deletions xml_schema_derive/src/xsd/schema.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::xsd::{
attribute, attribute_group, complex_type, element, import, qualification, simple_type,
use crate::xsd::{
attribute, attribute_group, complex_type, element, group, import, qualification, simple_type,
Implementation, XsdContext,
};
use proc_macro2::TokenStream;
Expand Down Expand Up @@ -29,6 +29,8 @@ pub struct Schema {
pub attributes: Vec<attribute::Attribute>,
#[yaserde(rename = "attributeGroup")]
pub attribute_group: Vec<attribute_group::AttributeGroup>,
#[yaserde(rename = "group")]
pub group: Vec<group::Group>,
}

impl Implementation for Schema {
Expand Down Expand Up @@ -71,10 +73,23 @@ impl Implementation for Schema {
.collect()
};

log::info!("Generate groups");
let groups: TokenStream = {
let mut context = context.clone();
context.set_is_in_sub_module(true);

self
.group
.iter()
.map(|group| group.implement(&namespace_definition, target_prefix, &context))
.collect()
};

quote!(
pub mod xml_schema_types {
#simple_types
#complex_types
#groups
}

#elements
Expand Down