diff --git a/xsd-parser/src/parser/all.rs b/xsd-parser/src/parser/all.rs new file mode 100644 index 00000000..275613d5 --- /dev/null +++ b/xsd-parser/src/parser/all.rs @@ -0,0 +1,16 @@ +use std::cell::RefCell; + +use roxmltree::Node; + +use crate::parser::types::{RsEntity, Struct}; +use crate::parser::utils::{elements_to_fields, get_documentation, get_parent_name}; + +pub fn parse_all(node: &Node, parent: &Node) -> RsEntity { + let name = get_parent_name(node); + RsEntity::Struct(Struct { + name: name.into(), + comment: get_documentation(parent), + subtypes: vec![], + fields: RefCell::new(elements_to_fields(node, name)), + }) +} diff --git a/xsd-parser/src/parser/attribute_group.rs b/xsd-parser/src/parser/attribute_group.rs deleted file mode 100644 index e740157e..00000000 --- a/xsd-parser/src/parser/attribute_group.rs +++ /dev/null @@ -1,92 +0,0 @@ -use roxmltree::Node; - -use crate::parser::node_parser::parse_node; -use crate::parser::types::{Alias, RsEntity, Struct, StructField}; -use crate::parser::utils::get_documentation; -use crate::parser::xsd_elements::{ElementType, XsdNode}; - -pub fn parse_attribute_group(node: &Node, parent: &Node) -> RsEntity { - if parent.xsd_type() == ElementType::Schema { - return parse_global_attribute_group(node); - } - - let reference = node - .attr_ref() - .expect("Non-global attributeGroups must be references.") - .to_string(); - - RsEntity::Alias(Alias { - name: reference.to_string(), - original: reference, - comment: get_documentation(node), - ..Default::default() - }) -} - -fn parse_global_attribute_group(node: &Node) -> RsEntity { - let name = node - .attr_name() - .unwrap_or_else(|| panic!("Name attribute required. {:?}", node)); - - let fields = attributes_to_fields(node); - - RsEntity::Struct(Struct { - name: name.to_string(), - fields: std::cell::RefCell::new(fields), - ..Default::default() - }) -} - -pub fn attributes_to_fields(node: &Node) -> Vec { - node.children() - .filter(|n| { - n.xsd_type() == ElementType::Attribute || n.xsd_type() == ElementType::AnyAttribute - }) - .map(|n| match parse_node(&n, node) { - RsEntity::StructField(sf) => sf, - _ => unreachable!("Invalid attribute parsing: {:?}", n), - }) - .collect() -} - -#[cfg(test)] -mod test { - use crate::parser::attribute_group::parse_global_attribute_group; - use crate::parser::types::RsEntity; - use crate::parser::utils::find_child; - - #[test] - fn test_global_attribute_with_nested_type() { - let doc = roxmltree::Document::parse( - r#" - - - - - - - - - - - - - - "#, - ) - .unwrap(); - - let schema = doc.root_element(); - let attribute = find_child(&schema, "attributeGroup").unwrap(); - match parse_global_attribute_group(&attribute) { - RsEntity::Struct(ts) => { - assert_eq!(ts.name, "contentGroup"); - assert_eq!(ts.fields.borrow().len(), 2); - } - _ => unreachable!("Test Failed!"), - } - } - -} diff --git a/xsd-parser/src/parser/complex_type.rs b/xsd-parser/src/parser/complex_type.rs index 64cb8a55..9784c9a1 100644 --- a/xsd-parser/src/parser/complex_type.rs +++ b/xsd-parser/src/parser/complex_type.rs @@ -4,7 +4,7 @@ use roxmltree::Node; use crate::parser::node_parser::parse_node; use crate::parser::types::{RsEntity, Struct, StructField, StructFieldSource}; -use crate::parser::utils::{attributes_to_fields, attribute_groups_to_aliases, get_documentation, get_parent_name}; +use crate::parser::utils::{attributes_to_fields, get_documentation, get_parent_name}; use crate::parser::xsd_elements::{ElementType, XsdNode}; // A complex type can contain one and only one of the following elements, @@ -45,7 +45,6 @@ pub fn parse_complex_type(node: &Node, parent: &Node) -> RsEntity { return RsEntity::Struct(Struct { fields: RefCell::new(fields), - attribute_groups: RefCell::new(attribute_groups_to_aliases(node)), comment: get_documentation(node), subtypes: vec![], name: name.to_string(), @@ -72,7 +71,6 @@ pub fn parse_complex_type(node: &Node, parent: &Node) -> RsEntity { subtypes: vec![], comment: get_documentation(node), fields: RefCell::new(fields), - attribute_groups: RefCell::new(attribute_groups_to_aliases(node)), })]; } _ => (), diff --git a/xsd-parser/src/parser/element.rs b/xsd-parser/src/parser/element.rs index 69794ab4..72584d9f 100644 --- a/xsd-parser/src/parser/element.rs +++ b/xsd-parser/src/parser/element.rs @@ -15,6 +15,7 @@ pub fn parse_element(node: &Node, parent: &Node) -> RsEntity { match parent.xsd_type() { ElementType::Schema => parse_global_element(node), ElementType::Sequence => parse_field_of_sequence(node, parent), + ElementType::All => parse_field_of_all(node, parent), ElementType::Choice => parse_case_of_choice(node), _ => element_default(node), } @@ -67,7 +68,15 @@ fn parse_case_of_choice(element: &Node) -> RsEntity { }) } +fn parse_field_of_all(node: &Node, _: &Node) -> RsEntity { + parse_field_of_element_container(node) +} + fn parse_field_of_sequence(node: &Node, _: &Node) -> RsEntity { + parse_field_of_element_container(node) +} + +fn parse_field_of_element_container(node: &Node) -> RsEntity { let name = node .attr_name() .unwrap_or_else(|| node.attr_ref().unwrap_or("UNSUPPORTED_ELEMENT_NAME")) diff --git a/xsd-parser/src/parser/extension.rs b/xsd-parser/src/parser/extension.rs index 5f2b32ca..30cb9b89 100644 --- a/xsd-parser/src/parser/extension.rs +++ b/xsd-parser/src/parser/extension.rs @@ -1,7 +1,7 @@ use crate::parser::constants::{attribute, tag}; use crate::parser::node_parser::parse_node; use crate::parser::types::{RsEntity, Struct, StructField, StructFieldSource}; -use crate::parser::utils::{attributes_to_fields, attribute_groups_to_aliases, get_base, get_documentation}; +use crate::parser::utils::{attributes_to_fields, get_base, get_documentation}; use crate::parser::xsd_elements::{ElementType, ExtensionType, XsdNode}; use roxmltree::Node; use std::cell::RefCell; @@ -41,7 +41,6 @@ fn simple_content_extension(node: &Node) -> RsEntity { subtypes: vec![], comment: get_documentation(node), fields: RefCell::new(fields), - attribute_groups: RefCell::new(attribute_groups_to_aliases(node)) }) } @@ -81,7 +80,6 @@ fn complex_content_extension(node: &Node) -> RsEntity { RsEntity::Struct(Struct { comment: get_documentation(node), fields: RefCell::new(fields), - attribute_groups: RefCell::new(attribute_groups_to_aliases(node)), ..Default::default() }) } diff --git a/xsd-parser/src/parser/mod.rs b/xsd-parser/src/parser/mod.rs index 1aecd642..2e320ea6 100644 --- a/xsd-parser/src/parser/mod.rs +++ b/xsd-parser/src/parser/mod.rs @@ -1,7 +1,7 @@ +mod all; mod any; mod any_attribute; mod attribute; -mod attribute_group; mod choice; mod complex_content; mod complex_type; @@ -44,15 +44,9 @@ pub fn parse(text: &str) -> Result { map.extend(st.get_types_map()); } } - for ag in &schema_rs.attribute_groups { - if let RsEntity::Struct(st) = ag { - map.extend(st.get_types_map()); - } - } for ty in &schema_rs.types { if let RsEntity::Struct(st) = ty { st.extend_base(&map); - st.extend_attribute_group(&map); } } diff --git a/xsd-parser/src/parser/node_parser.rs b/xsd-parser/src/parser/node_parser.rs index f1ae89cf..7962691b 100644 --- a/xsd-parser/src/parser/node_parser.rs +++ b/xsd-parser/src/parser/node_parser.rs @@ -1,9 +1,9 @@ use roxmltree::Node; +use crate::parser::all::parse_all; use crate::parser::any::parse_any; use crate::parser::any_attribute::parse_any_attribute; use crate::parser::attribute::parse_attribute; -use crate::parser::attribute_group::parse_attribute_group; use crate::parser::choice::parse_choice; use crate::parser::complex_content::parse_complex_content; use crate::parser::complex_type::parse_complex_type; @@ -23,10 +23,10 @@ pub fn parse_node(node: &Node, parent: &Node) -> RsEntity { use ElementType::*; match node.xsd_type() { + All => parse_all(node, parent), Any => parse_any(node), AnyAttribute => parse_any_attribute(node), Attribute => parse_attribute(node, parent), - AttributeGroup => parse_attribute_group(node, parent), Choice => parse_choice(node), ComplexContent => parse_complex_content(node), ComplexType => parse_complex_type(node, parent), diff --git a/xsd-parser/src/parser/restriction.rs b/xsd-parser/src/parser/restriction.rs index cf7e6481..461c54c6 100644 --- a/xsd-parser/src/parser/restriction.rs +++ b/xsd-parser/src/parser/restriction.rs @@ -6,7 +6,7 @@ use crate::parser::types::{ Enum, EnumCase, EnumSource, Facet, RsEntity, Struct, StructField, StructFieldSource, TupleStruct, }; -use crate::parser::utils::{attributes_to_fields, attribute_groups_to_aliases, get_base, get_documentation, get_parent_name}; +use crate::parser::utils::{attributes_to_fields, get_base, get_documentation, get_parent_name}; use crate::parser::xsd_elements::{ElementType, FacetType, RestrictionType, XsdNode}; use roxmltree::Node; @@ -93,7 +93,6 @@ fn complex_content_restriction(node: &Node) -> RsEntity { RsEntity::Struct(Struct { comment: get_documentation(node), fields: RefCell::new(fields), - attribute_groups: RefCell::new(attribute_groups_to_aliases(node)), ..Default::default() }) } diff --git a/xsd-parser/src/parser/schema.rs b/xsd-parser/src/parser/schema.rs index 3cb80f0a..6b6a561a 100644 --- a/xsd-parser/src/parser/schema.rs +++ b/xsd-parser/src/parser/schema.rs @@ -25,14 +25,6 @@ pub fn parse_schema<'input>(schema: &Node<'_, 'input>) -> RsFile<'input> { }) .map(|node| parse_node(&node, schema)) .collect(), - attribute_groups: schema - .children() - .filter(|n| { - n.is_element() - && n.xsd_type() == ElementType::AttributeGroup - }) - .map(|node| parse_node(&node, schema)) - .collect(), } } diff --git a/xsd-parser/src/parser/sequence.rs b/xsd-parser/src/parser/sequence.rs index a14a537a..65607f08 100644 --- a/xsd-parser/src/parser/sequence.rs +++ b/xsd-parser/src/parser/sequence.rs @@ -2,10 +2,8 @@ use std::cell::RefCell; use roxmltree::Node; -use crate::parser::node_parser::parse_node; -use crate::parser::types::{RsEntity, Struct, StructField, TypeModifier}; -use crate::parser::utils::{enum_to_field, get_documentation, get_parent_name}; -use crate::parser::xsd_elements::{ElementType, XsdNode}; +use crate::parser::types::{RsEntity, Struct}; +use crate::parser::utils::{elements_to_fields, get_documentation, get_parent_name}; pub fn parse_sequence(sequence: &Node, parent: &Node) -> RsEntity { let name = get_parent_name(sequence); @@ -14,26 +12,5 @@ pub fn parse_sequence(sequence: &Node, parent: &Node) -> RsEntity { comment: get_documentation(parent), subtypes: vec![], fields: RefCell::new(elements_to_fields(sequence, name)), - ..Default::default() }) } - -fn elements_to_fields(sequence: &Node, parent_name: &str) -> Vec { - sequence - .children() - .filter(|n| n.is_element() && n.xsd_type() != ElementType::Annotation) - .map(|n| match parse_node(&n, sequence) { - RsEntity::StructField(mut sf) => { - if sf.type_name.ends_with(parent_name) { - sf.type_modifiers.push(TypeModifier::Recursive) - } - sf - } - RsEntity::Enum(mut en) => { - en.name = format!("{}Choice", parent_name); - enum_to_field(en) - } - _ => unreachable!("\nError: {:?}\n{:?}", n, parse_node(&n, sequence)), - }) - .collect() -} diff --git a/xsd-parser/src/parser/types.rs b/xsd-parser/src/parser/types.rs index 39315931..8df0b633 100644 --- a/xsd-parser/src/parser/types.rs +++ b/xsd-parser/src/parser/types.rs @@ -10,7 +10,6 @@ pub struct RsFile<'input> { pub name: String, pub namespace: Option, pub types: Vec, - pub attribute_groups: Vec, pub target_ns: Option>, pub xsd_ns: Option>, } @@ -20,7 +19,6 @@ pub struct Struct { pub name: String, pub comment: Option, pub fields: RefCell>, - pub attribute_groups: RefCell>, pub subtypes: Vec, } @@ -76,23 +74,6 @@ impl Struct { } } } - - pub fn extend_attribute_group(&self, types: &HashMap<&String, &Self>) { - let mut fields = self - .attribute_groups - .borrow() - .iter() - .flat_map(|f| { - let key = f.original.split(':').last().unwrap().to_string(); - types - .get(&key) - .map(|s| s.fields.borrow().clone()) - .unwrap_or_else(Vec::new) - }) - .collect::>(); - - self.fields.borrow_mut().append(&mut fields); - } } #[derive(Debug, Clone, Default)] diff --git a/xsd-parser/src/parser/utils.rs b/xsd-parser/src/parser/utils.rs index 9f0952e3..a0d36c04 100644 --- a/xsd-parser/src/parser/utils.rs +++ b/xsd-parser/src/parser/utils.rs @@ -6,7 +6,7 @@ use roxmltree::{Namespace, Node}; use crate::parser::constants::attribute; use crate::parser::node_parser::parse_node; -use crate::parser::types::{Enum, RsEntity, StructField, StructFieldSource, Alias}; +use crate::parser::types::{Enum, RsEntity, StructField, StructFieldSource, TypeModifier}; use crate::parser::xsd_elements::{ElementType, XsdNode}; pub fn target_namespace<'a, 'input>(node: &Node<'a, 'input>) -> Option<&'a Namespace<'input>> { @@ -60,18 +60,6 @@ pub fn attributes_to_fields(node: &Node) -> Vec { .collect() } -pub fn attribute_groups_to_aliases(node: &Node) -> Vec { - node.children() - .filter(|n| { - n.xsd_type() == ElementType::AttributeGroup - }) - .map(|n| match parse_node(&n, node) { - RsEntity::Alias(a) => a, - _ => unreachable!("Invalid attribute group parsing: {:?}", n), - }) - .collect() -} - pub fn enum_to_field(en: Enum) -> StructField { StructField { name: en.name.clone(), @@ -81,3 +69,22 @@ pub fn enum_to_field(en: Enum) -> StructField { ..Default::default() } } + +pub fn elements_to_fields(node: &Node, parent_name: &str) -> Vec { + node.children() + .filter(|n| n.is_element() && n.xsd_type() != ElementType::Annotation) + .map(|n| match parse_node(&n, node) { + RsEntity::StructField(mut sf) => { + if sf.type_name.ends_with(parent_name) { + sf.type_modifiers.push(TypeModifier::Recursive) + } + sf + } + RsEntity::Enum(mut en) => { + en.name = format!("{}Choice", parent_name); + enum_to_field(en) + } + _ => unreachable!("\nError: {:?}\n{:?}", n, parse_node(&n, node)), + }) + .collect() +} diff --git a/xsd-parser/src/tests/all/example.xml b/xsd-parser/src/tests/all/example.xml new file mode 100644 index 00000000..6e169ee9 --- /dev/null +++ b/xsd-parser/src/tests/all/example.xml @@ -0,0 +1,8 @@ + + + b-string + a-string + diff --git a/xsd-parser/src/tests/all/expected.rs b/xsd-parser/src/tests/all/expected.rs new file mode 100644 index 00000000..dcc9cfc8 --- /dev/null +++ b/xsd-parser/src/tests/all/expected.rs @@ -0,0 +1,8 @@ +#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] +#[yaserde(prefix = "tns", namespace = "tns: http://example.com")] +pub struct FooType { + #[yaserde(prefix = "tns", rename = "A")] + pub a: String, + #[yaserde(prefix = "tns", rename = "B")] + pub b: String, +} diff --git a/xsd-parser/src/tests/all/input.xsd b/xsd-parser/src/tests/all/input.xsd new file mode 100644 index 00000000..7a3ba752 --- /dev/null +++ b/xsd-parser/src/tests/all/input.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/xsd-parser/src/tests/all/mod.rs b/xsd-parser/src/tests/all/mod.rs new file mode 100644 index 00000000..3f3ec9ad --- /dev/null +++ b/xsd-parser/src/tests/all/mod.rs @@ -0,0 +1,34 @@ +use super::utils; + +#[test] +fn deserialization_works() { + mod expected { + use std::io::{Read, Write}; + use yaserde::{YaDeserialize, YaSerialize}; + + include!("expected.rs"); + } + + let ser = include_str!("example.xml"); + + let de: expected::FooType = yaserde::de::from_str(&ser).unwrap(); + + assert_eq!( + de, + expected::FooType { + a: "a-string".to_string(), + b: "b-string".to_string(), + } + ); +} + +#[test] +fn generator_does_not_panic() { + println!("{}", utils::generate(include_str!("input.xsd"))) +} + +#[test] +#[ignore] +fn generator_output_has_correct_ast() { + utils::ast_test(include_str!("input.xsd"), include_str!("expected.rs")); +} diff --git a/xsd-parser/src/tests/mod.rs b/xsd-parser/src/tests/mod.rs index c8c74c5b..e78e8659 100644 --- a/xsd-parser/src/tests/mod.rs +++ b/xsd-parser/src/tests/mod.rs @@ -1,5 +1,6 @@ #[macro_use] mod utils; +mod all; mod any; mod choice; mod complex_type;