Skip to content

Commit

Permalink
Merge pull request #33 from matzipan/implement_group_extension
Browse files Browse the repository at this point in the history
Add extension group support
  • Loading branch information
MarcAntoine-Arnaud authored Jan 2, 2024
2 parents f671913 + 6623691 commit 214ab9b
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 8 deletions.
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

0 comments on commit 214ab9b

Please sign in to comment.