Skip to content

Commit 214ab9b

Browse files
Merge pull request #33 from matzipan/implement_group_extension
Add extension group support
2 parents f671913 + 6623691 commit 214ab9b

File tree

4 files changed

+154
-8
lines changed

4 files changed

+154
-8
lines changed

xml_schema_derive/src/xsd/extension.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::xsd::{
2-
attribute::Attribute, rust_types_mapping::RustTypesMapping, sequence::Sequence, Implementation,
3-
XsdContext,
2+
attribute::Attribute, group::Group, rust_types_mapping::RustTypesMapping, sequence::Sequence,
3+
Implementation, XsdContext,
44
};
55
use proc_macro2::TokenStream;
66

@@ -17,6 +17,8 @@ pub struct Extension {
1717
pub attributes: Vec<Attribute>,
1818
#[yaserde(rename = "sequence")]
1919
pub sequences: Vec<Sequence>,
20+
#[yaserde(rename = "group")]
21+
pub group: Option<Group>,
2022
}
2123

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

37-
let inner_attribute = if format!("{rust_type}") == "String" {
39+
let inner_attribute = if format!("{rust_type}") == "String" {
3840
quote!(#[yaserde(text)])
3941
} else {
4042
TokenStream::new()
4143
};
4244

4345
quote!(
4446
#inner_attribute
45-
pub content: #rust_type,
47+
pub base: #rust_type,
4648
#attributes
4749
)
4850
}
@@ -52,10 +54,28 @@ impl Extension {
5254
pub fn get_field_implementation(
5355
&self,
5456
context: &XsdContext,
55-
_prefix: &Option<String>,
57+
prefix: &Option<String>,
5658
) -> TokenStream {
5759
let rust_type = RustTypesMapping::get(context, &self.base);
58-
quote!(pub content : #rust_type)
60+
61+
let group_content = self
62+
.group
63+
.as_ref()
64+
.map(|group| {
65+
let group_type = group.get_type_implementation(context, prefix);
66+
67+
quote!(
68+
,
69+
#[serde(flatten)]
70+
pub extension : #group_type
71+
)
72+
})
73+
.unwrap_or_default();
74+
75+
quote!(
76+
pub base : #rust_type
77+
#group_content
78+
)
5979
}
6080
}
6181

@@ -70,6 +90,7 @@ mod tests {
7090
base: "xs:string".to_string(),
7191
attributes: vec![],
7292
sequences: vec![],
93+
group: None,
7394
};
7495

7596
let context =
@@ -112,6 +133,7 @@ mod tests {
112133
},
113134
],
114135
sequences: vec![],
136+
group: None,
115137
};
116138

117139
let context =

xml_schema_derive/src/xsd/group.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
use crate::xsd::{
2+
rust_types_mapping::RustTypesMapping, sequence::Sequence, Implementation, XsdContext,
3+
};
4+
use heck::ToUpperCamelCase;
5+
use proc_macro2::{Span, TokenStream};
6+
use syn::Ident;
7+
8+
#[derive(Clone, Default, Debug, PartialEq, YaDeserialize)]
9+
#[yaserde(prefix = "xs", namespace = "xs: http://www.w3.org/2001/XMLSchema")]
10+
pub struct Group {
11+
#[yaserde(attribute)]
12+
pub name: Option<String>,
13+
#[yaserde(attribute, rename = "ref")]
14+
pub reference: Option<String>,
15+
#[yaserde()]
16+
pub sequence: Option<Sequence>,
17+
}
18+
19+
impl Implementation for Group {
20+
fn implement(
21+
&self,
22+
namespace_definition: &TokenStream,
23+
prefix: &Option<String>,
24+
context: &XsdContext,
25+
) -> TokenStream {
26+
if self.name.is_none() {
27+
return quote!();
28+
}
29+
let raw_name = self.name.clone().unwrap();
30+
31+
let struct_name = Ident::new(&raw_name.to_upper_camel_case(), Span::call_site());
32+
33+
let fields = self
34+
.sequence
35+
.as_ref()
36+
.map(|sequence| sequence.get_field_implementation(context, prefix))
37+
.unwrap_or_default();
38+
39+
quote!(
40+
#[derive(Clone, Debug, Default, PartialEq, serde::Deserialize, serde::Serialize)]
41+
#namespace_definition
42+
pub struct #struct_name {
43+
#fields
44+
}
45+
)
46+
}
47+
}
48+
49+
impl Group {
50+
pub fn get_type_implementation(
51+
&self,
52+
context: &XsdContext,
53+
_prefix: &Option<String>,
54+
) -> TokenStream {
55+
if let Some(reference) = &self.reference {
56+
RustTypesMapping::get(context, reference)
57+
} else {
58+
panic!("Missing reference for group");
59+
}
60+
}
61+
}
62+
63+
#[cfg(test)]
64+
mod tests {
65+
use super::*;
66+
67+
use yaserde::de::from_str;
68+
69+
#[test]
70+
fn check_group_implementation() {
71+
let xml = r#"
72+
<group name="groupthing">
73+
<sequence>
74+
<element name="CX_X" type="asdfg"/>
75+
<element name="CY_X" type="asdfg"/>
76+
</sequence>
77+
</group>
78+
"#;
79+
80+
let group: Group = from_str(xml).unwrap();
81+
82+
let context =
83+
XsdContext::new(r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"></xs:schema>"#)
84+
.unwrap();
85+
86+
let implementation = format!("{}", group.implement(&TokenStream::new(), &None, &context));
87+
88+
assert_eq!(implementation, "# [derive (Clone , Debug , Default , PartialEq , serde :: Deserialize , serde :: Serialize)] \
89+
pub struct Groupthing { \
90+
# [yaserde (rename = \"CX_X\")] pub cx_x : xml_schema_types :: Asdfg , \
91+
# [yaserde (rename = \"CY_X\")] pub cy_x : xml_schema_types :: Asdfg , }");
92+
}
93+
94+
#[test]
95+
fn check_group_ref() {
96+
let xml = r#"<group ref="bla:groupthing" />"#;
97+
98+
let group: Group = from_str(xml).unwrap();
99+
100+
let context =
101+
XsdContext::new(r#"<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"></xs:schema>"#)
102+
.unwrap();
103+
104+
let type_implementation = format!("{}", group.get_type_implementation(&context, &None));
105+
106+
assert_eq!(type_implementation, "Groupthing");
107+
}
108+
}

xml_schema_derive/src/xsd/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod complex_content;
55
mod complex_type;
66
mod element;
77
mod extension;
8+
mod group;
89
mod import;
910
mod list;
1011
mod max_occurences;

xml_schema_derive/src/xsd/schema.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use crate::xsd::{
2-
attribute, attribute_group, complex_type, element, import, qualification, simple_type,
1+
use crate::xsd::{
2+
attribute, attribute_group, complex_type, element, group, import, qualification, simple_type,
33
Implementation, XsdContext,
44
};
55
use proc_macro2::TokenStream;
@@ -29,6 +29,8 @@ pub struct Schema {
2929
pub attributes: Vec<attribute::Attribute>,
3030
#[yaserde(rename = "attributeGroup")]
3131
pub attribute_group: Vec<attribute_group::AttributeGroup>,
32+
#[yaserde(rename = "group")]
33+
pub group: Vec<group::Group>,
3234
}
3335

3436
impl Implementation for Schema {
@@ -71,10 +73,23 @@ impl Implementation for Schema {
7173
.collect()
7274
};
7375

76+
log::info!("Generate groups");
77+
let groups: TokenStream = {
78+
let mut context = context.clone();
79+
context.set_is_in_sub_module(true);
80+
81+
self
82+
.group
83+
.iter()
84+
.map(|group| group.implement(&namespace_definition, target_prefix, &context))
85+
.collect()
86+
};
87+
7488
quote!(
7589
pub mod xml_schema_types {
7690
#simple_types
7791
#complex_types
92+
#groups
7893
}
7994

8095
#elements

0 commit comments

Comments
 (0)