xsd_parser/pipeline/optimizer/
dynamic_to_choice.rs1use crate::models::{
2 meta::{ComplexMeta, ElementMeta, ElementMode, GroupMeta, MetaType, MetaTypeVariant},
3 TypeIdent,
4};
5use crate::traits::{NameBuilderExt as _, VecHelper};
6
7use super::Optimizer;
8
9impl Optimizer {
10 #[doc = include_str!("../../../tests/optimizer/abstract.xsd")]
18 #[doc = include_str!("../../../tests/optimizer/expected0/convert_dynamic_to_choice.rs")]
23 #[doc = include_str!("../../../tests/optimizer/expected1/convert_dynamic_to_choice.rs")]
28 pub fn convert_dynamic_to_choice(mut self) -> Self {
30 use std::collections::btree_map::Entry;
31
32 tracing::debug!("convert_dynamic_to_choice");
33
34 let idents = self
35 .types
36 .items
37 .iter()
38 .filter_map(|(ident, ty)| {
39 if matches!(&ty.variant, MetaTypeVariant::Dynamic(_)) {
40 Some(ident)
41 } else {
42 None
43 }
44 })
45 .cloned()
46 .collect::<Vec<_>>();
47
48 for ident in idents {
49 let content_name = self.types.name_builder().shared_name("Content").finish();
50 let content_ident = TypeIdent::new(content_name).with_ns(ident.ns);
51
52 let mut si = GroupMeta::default();
53 let type_ = self.types.items.get(&ident).unwrap();
54 self.add_elements(&mut si, type_);
55
56 let type_ = self.types.items.get_mut(&ident).unwrap();
57 type_.variant = MetaTypeVariant::ComplexType(ComplexMeta {
58 content: Some(content_ident.clone()),
59 is_dynamic: true,
60 ..Default::default()
61 });
62
63 match self.types.items.entry(content_ident) {
64 Entry::Vacant(e) => {
65 e.insert(MetaType::new(if si.elements.is_empty() {
66 MetaTypeVariant::Sequence(si)
67 } else {
68 MetaTypeVariant::Choice(si)
69 }));
70 }
71 Entry::Occupied(_) => crate::unreachable!(),
72 }
73 }
74
75 self
76 }
77
78 fn add_elements(&self, group: &mut GroupMeta, ty: &MetaType) {
79 let form = ty.form();
80 let MetaTypeVariant::Dynamic(x) = &ty.variant else {
81 crate::unreachable!();
82 };
83
84 for meta in &x.derived_types {
85 let derived_ty = self.types.get_resolved_type(&meta.type_).unwrap();
86 if let MetaTypeVariant::Dynamic(_) = &derived_ty.variant {
87 self.add_elements(group, derived_ty);
88 } else {
89 group
90 .elements
91 .find_or_insert(meta.type_.to_property_ident(), |ident| {
92 let mut el =
93 ElementMeta::new(ident, meta.type_.clone(), ElementMode::Element, form);
94
95 if let Some(display_name) = &meta.display_name {
96 el.display_name = Some(display_name.clone());
97 }
98
99 el
100 });
101 }
102 }
103 }
104}