Skip to main content

xsd_schema/parser/frames/
types.rs

1// ============================================================================
2// Simple Type Frame
3// ============================================================================
4
5/// Parsing phase for simpleType
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7enum SimpleTypePhase {
8    /// Expecting annotation
9    Annotation,
10    /// Expecting restriction, list, or union
11    Derivation,
12    /// Done
13    Done,
14}
15
16/// Frame for xs:simpleType element
17pub struct SimpleTypeFrame {
18    phase: SimpleTypePhase,
19    name: Option<NameId>,
20    final_derivation: Option<DerivationSet>,
21    id: Option<String>,
22    derivation_id: Option<String>,
23    variety: Option<SimpleTypeVariety>,
24    base_type: Option<TypeRefResult>,
25    item_type: Option<TypeRefResult>,
26    member_types: Vec<TypeRefResult>,
27    facets: FacetSet,
28    annotation: Option<Annotation>,
29    source: Option<SourceRef>,
30    foreign_attributes: Vec<ForeignAttribute>,
31}
32
33impl SimpleTypeFrame {
34    pub fn new(
35        attrs: &AttributeMap,
36        name_table: &NameTable,
37        source: Option<SourceRef>,
38    ) -> SchemaResult<Self> {
39        let name = attrs
40            .get_value_by_name(name_table, "name")
41            .and_then(|s| name_table.get(s));
42
43        let final_derivation = parse_derivation_set_opt(
44            attrs.get_value_by_name(name_table, "final"),
45        )?;
46
47        let id = attrs
48            .get_value_by_name(name_table, "id")
49            .map(String::from);
50
51        Ok(Self {
52            phase: SimpleTypePhase::Annotation,
53            name,
54            final_derivation,
55            id,
56            derivation_id: None,
57            variety: None,
58            base_type: None,
59            item_type: None,
60            member_types: Vec::new(),
61            facets: FacetSet::new(),
62            annotation: None,
63            source,
64            foreign_attributes: Vec::new(),
65        })
66    }
67}
68
69impl Frame for SimpleTypeFrame {
70    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
71        match self.phase {
72            SimpleTypePhase::Annotation => matches!(
73                local_name,
74                xsd_names::ANNOTATION | xsd_names::RESTRICTION | xsd_names::LIST | xsd_names::UNION
75            ),
76            SimpleTypePhase::Derivation => matches!(
77                local_name,
78                xsd_names::RESTRICTION | xsd_names::LIST | xsd_names::UNION
79            ),
80            SimpleTypePhase::Done => false,
81        }
82    }
83
84    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
85        matches!(local_name, "name" | "final" | "id")
86    }
87
88    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
89        match local_name {
90            xsd_names::ANNOTATION => {
91                self.phase = SimpleTypePhase::Derivation;
92            }
93            xsd_names::RESTRICTION | xsd_names::LIST | xsd_names::UNION => {
94                self.phase = SimpleTypePhase::Done;
95            }
96            _ => {}
97        }
98    }
99
100    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
101        match child {
102            FrameResult::Annotation(ann) => {
103                self.annotation = Some(ann);
104            }
105            FrameResult::Type(TypeFrameResult::Simple(st)) => {
106                // Inline type from restriction/list/union
107                self.variety = Some(st.variety);
108                self.base_type = st.base_type;
109                self.item_type = st.item_type;
110                self.member_types = st.member_types;
111                self.facets = st.facets;
112                self.derivation_id = st.derivation_id;
113            }
114            FrameResult::Restriction(res) => {
115                // src-restriction-base-or-simpleType: in simpleType/restriction,
116                // cannot have both 'base' attribute and inline simpleType child
117                if res.base_type.is_some() && res.inline_type.is_some() {
118                    return Err(SchemaError::structural(
119                        "src-restriction-base-or-simpleType",
120                        "Simple type restriction cannot have both 'base' attribute and inline type",
121                        None,
122                    ));
123                }
124                let base = if let Some(inline) = res.inline_type.clone() {
125                    Some(TypeRefResult::Inline(Box::new(TypeFrameResult::Simple(Box::new(inline)))))
126                } else {
127                    res.base_type.clone()
128                };
129                self.variety = Some(SimpleTypeVariety::Atomic);
130                self.base_type = base;
131                self.facets = res.facets.clone();
132                self.derivation_id = res.id.clone();
133            }
134            FrameResult::Skip => {}
135            _ => {}
136        }
137        Ok(())
138    }
139
140    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
141        // src-simple-type: a simpleType definition must have exactly one of
142        // <restriction>, <list>, or <union> as a derivation child. A bare
143        // <simpleType> with no derivation (e.g. only an <annotation>) is
144        // structurally invalid (stB001).
145        if self.variety.is_none() {
146            return Err(SchemaError::structural(
147                "src-simple-type",
148                "simpleType must contain one of <restriction>, <list>, or <union>",
149                None,
150            ));
151        }
152        let annotation = merge_foreign_attributes(
153            self.annotation,
154            self.foreign_attributes,
155            self.source.clone(),
156        );
157        Ok(FrameResult::Type(TypeFrameResult::Simple(Box::new(SimpleTypeResult {
158            name: self.name,
159            variety: self.variety.unwrap_or(SimpleTypeVariety::Atomic),
160            base_type: self.base_type,
161            item_type: self.item_type,
162            member_types: self.member_types,
163            facets: self.facets,
164            final_derivation: self.final_derivation,
165            id: self.id,
166            derivation_id: self.derivation_id,
167            annotation,
168            source: self.source,
169        }))))
170    }
171
172    fn has_annotation(&self) -> bool {
173        self.annotation.is_some()
174    }
175
176    fn source(&self) -> Option<&SourceRef> {
177        self.source.as_ref()
178    }
179
180    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
181        self.foreign_attributes = attrs;
182    }
183}
184
185// ============================================================================
186// Restriction Frame
187// ============================================================================
188
189/// Frame for xs:restriction
190/// Parsing phase for restriction
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192enum RestrictionPhase {
193    Annotation,
194    Content,
195    Facets,
196    Attributes,
197    Done,
198}
199
200pub struct RestrictionFrame {
201    phase: RestrictionPhase,
202    base_type: Option<TypeRefResult>,
203    facets: FacetSet,
204    particle: Option<ParticleResult>,
205    open_content: Option<OpenContentResult>,
206    attributes: Vec<AttributeUseResult>,
207    attribute_groups: Vec<QNameRef>,
208    attribute_wildcard: Option<WildcardResult>,
209    assertions: Vec<AssertResult>,
210    id: Option<String>,
211    annotation: Option<Annotation>,
212    inline_type: Option<SimpleTypeResult>,
213    source: Option<SourceRef>,
214    foreign_attributes: Vec<ForeignAttribute>,
215}
216
217impl RestrictionFrame {
218    pub fn new(
219        attrs: &AttributeMap,
220        name_table: &NameTable,
221        source: Option<SourceRef>,
222        ns_snapshot: &NamespaceContextSnapshot,
223    ) -> SchemaResult<Self> {
224        let base_type = attrs
225            .get_value_by_name(name_table, "base")
226            .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
227            .transpose()?
228            .map(TypeRefResult::QName);
229
230        let id = attrs
231            .get_value_by_name(name_table, "id")
232            .map(String::from);
233
234        Ok(Self {
235            phase: RestrictionPhase::Annotation,
236            base_type,
237            facets: FacetSet::new(),
238            particle: None,
239            open_content: None,
240            attributes: Vec::new(),
241            attribute_groups: Vec::new(),
242            attribute_wildcard: None,
243            assertions: Vec::new(),
244            id,
245            annotation: None,
246            inline_type: None,
247            source,
248            foreign_attributes: Vec::new(),
249        })
250    }
251}
252
253impl Frame for RestrictionFrame {
254    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
255        let is_facet = matches!(
256            local_name,
257            xsd_names::ENUMERATION
258                | xsd_names::PATTERN
259                | xsd_names::MIN_INCLUSIVE
260                | xsd_names::MAX_INCLUSIVE
261                | xsd_names::MIN_EXCLUSIVE
262                | xsd_names::MAX_EXCLUSIVE
263                | xsd_names::MIN_LENGTH
264                | xsd_names::MAX_LENGTH
265                | xsd_names::LENGTH
266                | xsd_names::TOTAL_DIGITS
267                | xsd_names::FRACTION_DIGITS
268                | xsd_names::WHITE_SPACE
269        );
270
271        #[cfg(feature = "xsd11")]
272        let is_xsd11_element = matches!(
273            local_name,
274            xsd_names::OPEN_CONTENT
275                | xsd_names::ASSERT
276                | xsd_names::ASSERTION
277                | xsd_names::EXPLICIT_TIMEZONE
278        );
279        #[cfg(not(feature = "xsd11"))]
280        let is_xsd11_element = false;
281
282        #[cfg(feature = "xsd11")]
283        let is_xsd11_facet = matches!(
284            local_name,
285            xsd_names::ASSERTION | xsd_names::EXPLICIT_TIMEZONE
286        );
287        #[cfg(not(feature = "xsd11"))]
288        let is_xsd11_facet = false;
289
290        match self.phase {
291            RestrictionPhase::Annotation => matches!(
292                local_name,
293                xsd_names::ANNOTATION
294                    | xsd_names::SIMPLE_TYPE
295                    | xsd_names::SEQUENCE
296                    | xsd_names::CHOICE
297                    | xsd_names::ALL
298                    | xsd_names::GROUP
299                    | xsd_names::ATTRIBUTE
300                    | xsd_names::ATTRIBUTE_GROUP
301                    | xsd_names::ANY_ATTRIBUTE
302            ) || is_facet || is_xsd11_element,
303            RestrictionPhase::Content => matches!(
304                local_name,
305                xsd_names::SIMPLE_TYPE
306                    | xsd_names::SEQUENCE
307                    | xsd_names::CHOICE
308                    | xsd_names::ALL
309                    | xsd_names::GROUP
310                    | xsd_names::ATTRIBUTE
311                    | xsd_names::ATTRIBUTE_GROUP
312                    | xsd_names::ANY_ATTRIBUTE
313            ) || is_facet || is_xsd11_element,
314            RestrictionPhase::Facets => is_facet || is_xsd11_facet || matches!(
315                local_name,
316                xsd_names::ATTRIBUTE
317                    | xsd_names::ATTRIBUTE_GROUP
318                    | xsd_names::ANY_ATTRIBUTE
319            ) || matches!(local_name, xsd_names::ASSERT | xsd_names::OPEN_CONTENT if is_xsd11_element),
320            RestrictionPhase::Attributes => matches!(
321                local_name,
322                xsd_names::ATTRIBUTE
323                    | xsd_names::ATTRIBUTE_GROUP
324                    | xsd_names::ANY_ATTRIBUTE
325            ) || is_xsd11_element,
326            RestrictionPhase::Done => false,
327        }
328    }
329
330    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
331        matches!(local_name, "base" | "id")
332    }
333
334    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
335        match local_name {
336            xsd_names::ANNOTATION => {
337                self.phase = RestrictionPhase::Content;
338            }
339            xsd_names::SIMPLE_TYPE => {
340                self.phase = RestrictionPhase::Facets;
341            }
342            xsd_names::SEQUENCE | xsd_names::CHOICE | xsd_names::ALL | xsd_names::GROUP => {
343                self.phase = RestrictionPhase::Attributes;
344            }
345            xsd_names::ENUMERATION | xsd_names::PATTERN | xsd_names::MIN_INCLUSIVE
346            | xsd_names::MAX_INCLUSIVE | xsd_names::MIN_EXCLUSIVE | xsd_names::MAX_EXCLUSIVE
347            | xsd_names::MIN_LENGTH | xsd_names::MAX_LENGTH | xsd_names::LENGTH
348            | xsd_names::TOTAL_DIGITS | xsd_names::FRACTION_DIGITS | xsd_names::WHITE_SPACE => {
349                self.phase = RestrictionPhase::Facets;
350            }
351            xsd_names::ATTRIBUTE | xsd_names::ATTRIBUTE_GROUP => {
352                self.phase = RestrictionPhase::Attributes;
353            }
354            xsd_names::ANY_ATTRIBUTE => {
355                self.phase = RestrictionPhase::Done;
356            }
357            _ => {}
358        }
359    }
360
361    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
362        match child {
363            FrameResult::Annotation(ann) => {
364                self.annotation = Some(ann);
365            }
366            FrameResult::Type(TypeFrameResult::Simple(st)) => {
367                self.inline_type = Some(*st);
368            }
369            FrameResult::Facet(facet) => {
370                apply_facet(&mut self.facets, facet)?;
371            }
372            FrameResult::Particle(particle) => {
373                self.particle = Some(particle);
374            }
375            FrameResult::OpenContent(open_content) => {
376                self.open_content = Some(open_content);
377            }
378            FrameResult::Attribute(attr) => {
379                let use_kind = match attr.use_kind.as_deref() {
380                    Some("required") => AttributeUseKind::Required,
381                    Some("prohibited") => AttributeUseKind::Prohibited,
382                    _ => AttributeUseKind::Optional,
383                };
384                self.attributes.push(AttributeUseResult {
385                    attribute: attr,
386                    use_kind,
387                });
388            }
389            FrameResult::Group(GroupFrameResult::Attribute(ag)) => {
390                if let Some(ref_name) = ag.ref_name {
391                    self.attribute_groups.push(ref_name);
392                }
393            }
394            FrameResult::Group(GroupFrameResult::Model(mg)) => {
395                let min_occurs = mg.min_occurs;
396                let max_occurs = mg.max_occurs;
397                self.particle = Some(ParticleResult {
398                    term: ParticleTerm::Group(*mg),
399                    min_occurs,
400                    max_occurs,
401                    source: None,
402                });
403            }
404            FrameResult::Wildcard(wc) => {
405                self.attribute_wildcard = Some(wc);
406            }
407            FrameResult::Assert(assertion) => {
408                self.assertions.push(assertion);
409            }
410            FrameResult::Skip => {}
411            _ => {}
412        }
413        Ok(())
414    }
415
416    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
417        // Note: The "base XOR inline simpleType" constraint (src-restriction-base-or-simpleType)
418        // only applies to simpleType/restriction, not to simpleContent/restriction where both
419        // are valid (base names the complex type, inline simpleType restricts its content).
420        // The parent frame (SimpleTypeFrame vs SimpleContentFrame) enforces this contextually.
421
422        let annotation = merge_foreign_attributes(
423            self.annotation,
424            self.foreign_attributes,
425            self.source.clone(),
426        );
427        Ok(FrameResult::Restriction(Box::new(RestrictionResult {
428            base_type: self.base_type,
429            inline_type: self.inline_type,
430            facets: self.facets,
431            particle: self.particle,
432            open_content: self.open_content,
433            attributes: self.attributes,
434            attribute_groups: self.attribute_groups,
435            attribute_wildcard: self.attribute_wildcard,
436            assertions: self.assertions,
437            id: self.id,
438            annotation,
439            source: self.source,
440        })))
441    }
442
443    fn has_annotation(&self) -> bool {
444        self.annotation.is_some()
445    }
446
447    fn source(&self) -> Option<&SourceRef> {
448        self.source.as_ref()
449    }
450
451    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
452        self.foreign_attributes = attrs;
453    }
454}
455
456// ============================================================================
457// Extension Frame
458// ============================================================================
459
460/// Frame for xs:extension
461/// Parsing phase for extension
462#[derive(Debug, Clone, Copy, PartialEq, Eq)]
463enum ExtensionPhase {
464    Annotation,
465    Content,
466    Attributes,
467    Done,
468}
469
470pub struct ExtensionFrame {
471    phase: ExtensionPhase,
472    base_type: Option<TypeRefResult>,
473    particle: Option<ParticleResult>,
474    open_content: Option<OpenContentResult>,
475    attributes: Vec<AttributeUseResult>,
476    attribute_groups: Vec<QNameRef>,
477    attribute_wildcard: Option<WildcardResult>,
478    assertions: Vec<AssertResult>,
479    id: Option<String>,
480    annotation: Option<Annotation>,
481    source: Option<SourceRef>,
482    foreign_attributes: Vec<ForeignAttribute>,
483}
484
485impl ExtensionFrame {
486    pub fn new(
487        attrs: &AttributeMap,
488        name_table: &NameTable,
489        source: Option<SourceRef>,
490        ns_snapshot: &NamespaceContextSnapshot,
491    ) -> SchemaResult<Self> {
492        let base_type = attrs
493            .get_value_by_name(name_table, "base")
494            .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
495            .transpose()?
496            .map(TypeRefResult::QName);
497
498        let id = attrs
499            .get_value_by_name(name_table, "id")
500            .map(String::from);
501
502        Ok(Self {
503            phase: ExtensionPhase::Annotation,
504            base_type,
505            particle: None,
506            open_content: None,
507            attributes: Vec::new(),
508            attribute_groups: Vec::new(),
509            attribute_wildcard: None,
510            assertions: Vec::new(),
511            id,
512            annotation: None,
513            source,
514            foreign_attributes: Vec::new(),
515        })
516    }
517}
518
519impl Frame for ExtensionFrame {
520    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
521        #[cfg(feature = "xsd11")]
522        let is_xsd11_element = matches!(
523            local_name,
524            xsd_names::OPEN_CONTENT | xsd_names::ASSERT
525        );
526        #[cfg(not(feature = "xsd11"))]
527        let is_xsd11_element = false;
528
529        match self.phase {
530            ExtensionPhase::Annotation => matches!(
531                local_name,
532                xsd_names::ANNOTATION
533                    | xsd_names::SEQUENCE
534                    | xsd_names::CHOICE
535                    | xsd_names::ALL
536                    | xsd_names::GROUP
537                    | xsd_names::ATTRIBUTE
538                    | xsd_names::ATTRIBUTE_GROUP
539                    | xsd_names::ANY_ATTRIBUTE
540            ) || is_xsd11_element,
541            ExtensionPhase::Content => matches!(
542                local_name,
543                xsd_names::SEQUENCE
544                    | xsd_names::CHOICE
545                    | xsd_names::ALL
546                    | xsd_names::GROUP
547                    | xsd_names::ATTRIBUTE
548                    | xsd_names::ATTRIBUTE_GROUP
549                    | xsd_names::ANY_ATTRIBUTE
550            ) || is_xsd11_element,
551            ExtensionPhase::Attributes => matches!(
552                local_name,
553                xsd_names::ATTRIBUTE
554                    | xsd_names::ATTRIBUTE_GROUP
555                    | xsd_names::ANY_ATTRIBUTE
556            ) || is_xsd11_element,
557            ExtensionPhase::Done => false,
558        }
559    }
560
561    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
562        matches!(local_name, "base" | "id")
563    }
564
565    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
566        match local_name {
567            xsd_names::ANNOTATION => {
568                self.phase = ExtensionPhase::Content;
569            }
570            xsd_names::SEQUENCE | xsd_names::CHOICE | xsd_names::ALL | xsd_names::GROUP => {
571                self.phase = ExtensionPhase::Attributes;
572            }
573            xsd_names::ATTRIBUTE | xsd_names::ATTRIBUTE_GROUP => {
574                self.phase = ExtensionPhase::Attributes;
575            }
576            xsd_names::ANY_ATTRIBUTE => {
577                self.phase = ExtensionPhase::Done;
578            }
579            _ => {}
580        }
581    }
582
583    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
584        match child {
585            FrameResult::Annotation(ann) => {
586                self.annotation = Some(ann);
587            }
588            FrameResult::Particle(particle) => {
589                self.particle = Some(particle);
590            }
591            FrameResult::OpenContent(open_content) => {
592                self.open_content = Some(open_content);
593            }
594            FrameResult::Attribute(attr) => {
595                let use_kind = match attr.use_kind.as_deref() {
596                    Some("required") => AttributeUseKind::Required,
597                    Some("prohibited") => AttributeUseKind::Prohibited,
598                    _ => AttributeUseKind::Optional,
599                };
600                self.attributes.push(AttributeUseResult {
601                    attribute: attr,
602                    use_kind,
603                });
604            }
605            FrameResult::Group(GroupFrameResult::Attribute(ag)) => {
606                if let Some(ref_name) = ag.ref_name {
607                    self.attribute_groups.push(ref_name);
608                }
609            }
610            FrameResult::Group(GroupFrameResult::Model(mg)) => {
611                let min_occurs = mg.min_occurs;
612                let max_occurs = mg.max_occurs;
613                self.particle = Some(ParticleResult {
614                    term: ParticleTerm::Group(*mg),
615                    min_occurs,
616                    max_occurs,
617                    source: None,
618                });
619            }
620            FrameResult::Wildcard(wc) => {
621                self.attribute_wildcard = Some(wc);
622            }
623            FrameResult::Assert(assertion) => {
624                self.assertions.push(assertion);
625            }
626            FrameResult::Skip => {}
627            _ => {}
628        }
629        Ok(())
630    }
631
632    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
633        let annotation = merge_foreign_attributes(
634            self.annotation,
635            self.foreign_attributes,
636            self.source.clone(),
637        );
638        Ok(FrameResult::Extension(ExtensionResult {
639            base_type: self.base_type,
640            particle: self.particle,
641            open_content: self.open_content,
642            attributes: self.attributes,
643            attribute_groups: self.attribute_groups,
644            attribute_wildcard: self.attribute_wildcard,
645            assertions: self.assertions,
646            id: self.id,
647            annotation,
648            source: self.source,
649        }))
650    }
651
652    fn has_annotation(&self) -> bool {
653        self.annotation.is_some()
654    }
655
656    fn source(&self) -> Option<&SourceRef> {
657        self.source.as_ref()
658    }
659
660    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
661        self.foreign_attributes = attrs;
662    }
663}
664
665// ============================================================================
666// List Frame
667// ============================================================================
668
669/// Frame for xs:list within simpleType
670pub struct ListFrame {
671    item_type: Option<TypeRefResult>,
672    id: Option<String>,
673    annotation: Option<Annotation>,
674    inline_type: Option<SimpleTypeResult>,
675    source: Option<SourceRef>,
676    foreign_attributes: Vec<ForeignAttribute>,
677    /// Set on `<simpleType>` start (before the inline frame is pushed and
678    /// before `attach` populates `inline_type`). Used by `allows()` to
679    /// reject `<annotation>` siblings that follow a `<simpleType>`, since
680    /// `inline_type.is_some()` is also the natural "saw it" signal once
681    /// `attach` has run. The flag captures the earlier moment so that any
682    /// hypothetical pre-attach query also rejects (stD017).
683    saw_inline_type: bool,
684}
685
686impl ListFrame {
687    pub fn new(
688        attrs: &AttributeMap,
689        name_table: &NameTable,
690        source: Option<SourceRef>,
691        ns_snapshot: &NamespaceContextSnapshot,
692    ) -> SchemaResult<Self> {
693        let item_type = attrs
694            .get_value_by_name(name_table, "itemType")
695            .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
696            .transpose()?
697            .map(TypeRefResult::QName);
698
699        let id = attrs
700            .get_value_by_name(name_table, "id")
701            .map(String::from);
702
703        Ok(Self {
704            item_type,
705            id,
706            annotation: None,
707            inline_type: None,
708            source,
709            foreign_attributes: Vec::new(),
710            saw_inline_type: false,
711        })
712    }
713}
714
715impl Frame for ListFrame {
716    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
717        match local_name {
718            xsd_names::ANNOTATION => !self.saw_inline_type,
719            xsd_names::SIMPLE_TYPE => true,
720            _ => false,
721        }
722    }
723
724    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
725        matches!(local_name, "itemType" | "id")
726    }
727
728    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
729        if local_name == xsd_names::SIMPLE_TYPE {
730            self.saw_inline_type = true;
731        }
732    }
733
734    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
735        match child {
736            FrameResult::Annotation(ann) => {
737                self.annotation = Some(ann);
738            }
739            FrameResult::Type(TypeFrameResult::Simple(st)) => {
740                if self.inline_type.is_some() {
741                    return Err(SchemaError::structural(
742                        "src-list-itemType-or-simpleType",
743                        "xs:list may contain at most one inline <simpleType>",
744                        None,
745                    ));
746                }
747                self.inline_type = Some(*st);
748            }
749            FrameResult::Skip => {}
750            _ => {}
751        }
752        Ok(())
753    }
754
755    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
756        // Validate list structure: itemType XOR inline simpleType
757        let has_item_type_attr = self.item_type.is_some();
758        let has_inline_type = self.inline_type.is_some();
759
760        if has_item_type_attr && has_inline_type {
761            return Err(SchemaError::structural(
762                "src-list-itemType-or-simpleType",
763                "List cannot have both 'itemType' attribute and inline simpleType",
764                None,
765            ));
766        }
767
768        if !has_item_type_attr && !has_inline_type {
769            return Err(SchemaError::structural(
770                "src-list-itemType-or-simpleType",
771                "List must have either 'itemType' attribute or inline simpleType",
772                None,
773            ));
774        }
775
776        let item = if let Some(inline) = self.inline_type {
777            Some(TypeRefResult::Inline(Box::new(TypeFrameResult::Simple(Box::new(inline)))))
778        } else {
779            self.item_type
780        };
781
782        let annotation = merge_foreign_attributes(
783            self.annotation,
784            self.foreign_attributes,
785            self.source.clone(),
786        );
787        Ok(FrameResult::Type(TypeFrameResult::Simple(Box::new(SimpleTypeResult {
788            name: None,
789            variety: SimpleTypeVariety::List,
790            base_type: None,
791            item_type: item,
792            member_types: Vec::new(),
793            facets: FacetSet::new(),
794            final_derivation: None,
795            id: None,
796            derivation_id: self.id,
797            annotation,
798            source: self.source,
799        }))))
800    }
801
802    fn has_annotation(&self) -> bool {
803        self.annotation.is_some()
804    }
805
806    fn source(&self) -> Option<&SourceRef> {
807        self.source.as_ref()
808    }
809
810    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
811        self.foreign_attributes = attrs;
812    }
813}
814
815// ============================================================================
816// Union Frame
817// ============================================================================
818
819/// Frame for xs:union within simpleType
820pub struct UnionFrame {
821    member_types: Vec<TypeRefResult>,
822    id: Option<String>,
823    annotation: Option<Annotation>,
824    source: Option<SourceRef>,
825    foreign_attributes: Vec<ForeignAttribute>,
826    /// Whether a `<simpleType>` member has been seen — once true, no more
827    /// `<annotation>` siblings are allowed (annotation must come first per
828    /// the xs:union content model). stE016.
829    saw_inline_type: bool,
830}
831
832impl UnionFrame {
833    pub fn new(
834        attrs: &AttributeMap,
835        name_table: &NameTable,
836        source: Option<SourceRef>,
837        ns_snapshot: &NamespaceContextSnapshot,
838    ) -> SchemaResult<Self> {
839        let member_types = if let Some(s) = attrs.get_value_by_name(name_table, "memberTypes") {
840            parse_qname_list(s, name_table, ns_snapshot)?
841                .into_iter()
842                .map(TypeRefResult::QName)
843                .collect()
844        } else {
845            Vec::new()
846        };
847
848        let id = attrs
849            .get_value_by_name(name_table, "id")
850            .map(String::from);
851
852        Ok(Self {
853            member_types,
854            id,
855            annotation: None,
856            source,
857            foreign_attributes: Vec::new(),
858            saw_inline_type: false,
859        })
860    }
861}
862
863impl Frame for UnionFrame {
864    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
865        match local_name {
866            xsd_names::ANNOTATION => !self.saw_inline_type,
867            xsd_names::SIMPLE_TYPE => true,
868            _ => false,
869        }
870    }
871
872    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
873        matches!(local_name, "memberTypes" | "id")
874    }
875
876    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
877        if local_name == xsd_names::SIMPLE_TYPE {
878            self.saw_inline_type = true;
879        }
880    }
881
882    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
883        match child {
884            FrameResult::Annotation(ann) => {
885                self.annotation = Some(ann);
886            }
887            FrameResult::Type(TypeFrameResult::Simple(st)) => {
888                self.member_types.push(TypeRefResult::Inline(Box::new(
889                    TypeFrameResult::Simple(st),
890                )));
891            }
892            FrameResult::Skip => {}
893            _ => {}
894        }
895        Ok(())
896    }
897
898    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
899        // Validate union structure: must have memberTypes and/or inline simpleTypes
900        if self.member_types.is_empty() {
901            return Err(SchemaError::structural(
902                "src-union-memberTypes-or-simpleTypes",
903                "Union must have 'memberTypes' attribute or inline simpleType children",
904                None,
905            ));
906        }
907
908        let annotation = merge_foreign_attributes(
909            self.annotation,
910            self.foreign_attributes,
911            self.source.clone(),
912        );
913        Ok(FrameResult::Type(TypeFrameResult::Simple(Box::new(SimpleTypeResult {
914            name: None,
915            variety: SimpleTypeVariety::Union,
916            base_type: None,
917            item_type: None,
918            member_types: self.member_types,
919            facets: FacetSet::new(),
920            final_derivation: None,
921            id: None,
922            derivation_id: self.id,
923            annotation,
924            source: self.source,
925        }))))
926    }
927
928    fn has_annotation(&self) -> bool {
929        self.annotation.is_some()
930    }
931
932    fn source(&self) -> Option<&SourceRef> {
933        self.source.as_ref()
934    }
935
936    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
937        self.foreign_attributes = attrs;
938    }
939}
940
941// ============================================================================
942// Simple/Complex Content Frames
943// ============================================================================
944
945/// src-ct: the XSD schema-for-schemas content model of
946/// `<xs:simpleContent>/<xs:restriction>` and `<xs:simpleContent>/<xs:extension>`
947/// permits only facets (restriction only), attributes, attribute groups, an
948/// attribute wildcard, and (XSD 1.1) assertions. Model groups and
949/// `<xs:openContent>` are not allowed.
950fn reject_simple_content_particle_or_open_content(
951    context: &str,
952    particle: Option<&ParticleResult>,
953    open_content: Option<&OpenContentResult>,
954) -> SchemaResult<()> {
955    if particle.is_some() {
956        return Err(SchemaError::structural(
957            "src-ct",
958            format!(
959                "{context} must not contain a model group \
960                 (xs:sequence, xs:choice, xs:all, or xs:group)"
961            ),
962            None,
963        ));
964    }
965    if open_content.is_some() {
966        return Err(SchemaError::structural(
967            "src-ct",
968            format!("{context} must not contain xs:openContent"),
969            None,
970        ));
971    }
972    Ok(())
973}
974
975/// Frame for xs:simpleContent
976pub struct SimpleContentFrame {
977    id: Option<String>,
978    base_type: Option<TypeRefResult>,
979    content_type: Option<Box<SimpleTypeResult>>,
980    derivation: Option<DerivationMethod>,
981    facets: FacetSet,
982    attributes: Vec<AttributeUseResult>,
983    attribute_groups: Vec<QNameRef>,
984    attribute_wildcard: Option<WildcardResult>,
985    assertions: Vec<AssertResult>,
986    derivation_id: Option<String>,
987    annotation: Option<Annotation>,
988    source: Option<SourceRef>,
989    foreign_attributes: Vec<ForeignAttribute>,
990    /// `true` after a <restriction> or <extension> child has been seen.
991    /// The XSD schema-for-schemas content model `(annotation?, (restriction |
992    /// extension))` forbids any further children — including a trailing
993    /// <annotation> — so we reject them via `allows`.
994    derivation_seen: bool,
995}
996
997impl SimpleContentFrame {
998    pub fn new(
999        attrs: &AttributeMap,
1000        name_table: &NameTable,
1001        source: Option<SourceRef>,
1002    ) -> SchemaResult<Self> {
1003        let id = attrs
1004            .get_value_by_name(name_table, "id")
1005            .map(String::from);
1006
1007        Ok(Self {
1008            id,
1009            base_type: None,
1010            content_type: None,
1011            derivation: None,
1012            facets: FacetSet::new(),
1013            attributes: Vec::new(),
1014            attribute_groups: Vec::new(),
1015            attribute_wildcard: None,
1016            assertions: Vec::new(),
1017            derivation_id: None,
1018            annotation: None,
1019            source,
1020            foreign_attributes: Vec::new(),
1021            derivation_seen: false,
1022        })
1023    }
1024}
1025
1026impl Frame for SimpleContentFrame {
1027    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
1028        if self.derivation_seen {
1029            return false;
1030        }
1031        matches!(
1032            local_name,
1033            xsd_names::ANNOTATION | xsd_names::RESTRICTION | xsd_names::EXTENSION
1034        )
1035    }
1036
1037    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
1038        matches!(local_name, "id")
1039    }
1040
1041    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
1042        if matches!(local_name, xsd_names::RESTRICTION | xsd_names::EXTENSION) {
1043            self.derivation_seen = true;
1044        }
1045    }
1046
1047    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
1048        match child {
1049            FrameResult::Annotation(ann) => {
1050                self.annotation = Some(ann);
1051            }
1052            FrameResult::Restriction(res) => {
1053                // src-ct: the XSD schema-for-schemas content model of
1054                // <xs:simpleContent>/{restriction|extension} does not permit
1055                // model groups or <xs:openContent>.
1056                reject_simple_content_particle_or_open_content(
1057                    "xs:simpleContent/xs:restriction",
1058                    res.particle.as_ref(),
1059                    res.open_content.as_ref(),
1060                )?;
1061                if res.base_type.is_some() && res.inline_type.is_some() {
1062                    // simpleContent/restriction with both base and inline simpleType:
1063                    // base names the complex type being restricted,
1064                    // inline simpleType = B (content type restriction per spec 3.4.2.2 clause 1.1)
1065                    self.base_type = res.base_type.clone();
1066                    self.content_type = res.inline_type.map(Box::new);
1067                    self.facets = res.facets.clone();
1068                } else {
1069                    let base = if let Some(inline) = res.inline_type.clone() {
1070                        Some(TypeRefResult::Inline(Box::new(TypeFrameResult::Simple(Box::new(inline)))))
1071                    } else {
1072                        res.base_type.clone()
1073                    };
1074                    self.base_type = base;
1075                    self.facets = res.facets.clone();
1076                }
1077                self.derivation = Some(DerivationMethod::Restriction);
1078                self.attributes = res.attributes.clone();
1079                self.attribute_groups = res.attribute_groups.clone();
1080                self.attribute_wildcard = res.attribute_wildcard.clone();
1081                self.assertions = res.assertions.clone();
1082                self.derivation_id = res.id.clone();
1083            }
1084            FrameResult::Extension(res) => {
1085                reject_simple_content_particle_or_open_content(
1086                    "xs:simpleContent/xs:extension",
1087                    res.particle.as_ref(),
1088                    res.open_content.as_ref(),
1089                )?;
1090                self.base_type = res.base_type;
1091                self.derivation = Some(DerivationMethod::Extension);
1092                self.attributes = res.attributes;
1093                self.attribute_groups = res.attribute_groups;
1094                self.attribute_wildcard = res.attribute_wildcard;
1095                self.assertions = res.assertions;
1096                self.derivation_id = res.id;
1097            }
1098            FrameResult::Skip => {}
1099            _ => {}
1100        }
1101        Ok(())
1102    }
1103
1104    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
1105        let base_type = self.base_type.ok_or_else(|| SchemaError::structural(
1106            "ct-props-correct",
1107            "xs:simpleContent requires a base type",
1108            None,
1109        ))?;
1110
1111        Ok(FrameResult::SimpleContent(SimpleContentDefResult {
1112            base_type: Some(base_type),
1113            content_type: self.content_type,
1114            derivation: self.derivation.unwrap_or(DerivationMethod::Restriction),
1115            facets: self.facets,
1116            attributes: self.attributes,
1117            attribute_groups: self.attribute_groups,
1118            attribute_wildcard: self.attribute_wildcard,
1119            assertions: self.assertions,
1120            id: self.id,
1121            derivation_id: self.derivation_id,
1122            source: self.source,
1123        }))
1124    }
1125
1126    fn has_annotation(&self) -> bool {
1127        self.annotation.is_some()
1128    }
1129
1130    fn source(&self) -> Option<&SourceRef> {
1131        self.source.as_ref()
1132    }
1133
1134    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
1135        self.foreign_attributes = attrs;
1136    }
1137}
1138
1139/// Frame for xs:complexContent
1140pub struct ComplexContentFrame {
1141    id: Option<String>,
1142    mixed: bool,
1143    /// `true` when the `<xs:complexContent mixed="…">` attribute was
1144    /// explicitly present.  See `ComplexContentDefResult::mixed_explicit`.
1145    mixed_explicit: bool,
1146    base_type: Option<TypeRefResult>,
1147    derivation: Option<DerivationMethod>,
1148    particle: Option<ParticleResult>,
1149    open_content: Option<OpenContentResult>,
1150    attributes: Vec<AttributeUseResult>,
1151    attribute_groups: Vec<QNameRef>,
1152    attribute_wildcard: Option<WildcardResult>,
1153    assertions: Vec<AssertResult>,
1154    derivation_id: Option<String>,
1155    annotation: Option<Annotation>,
1156    source: Option<SourceRef>,
1157    foreign_attributes: Vec<ForeignAttribute>,
1158    /// See `SimpleContentFrame::derivation_seen`.
1159    derivation_seen: bool,
1160}
1161
1162impl ComplexContentFrame {
1163    pub fn new(
1164        attrs: &AttributeMap,
1165        name_table: &NameTable,
1166        source: Option<SourceRef>,
1167    ) -> SchemaResult<Self> {
1168        let id = attrs
1169            .get_value_by_name(name_table, "id")
1170            .map(String::from);
1171
1172        let mixed_opt = parse_optional_bool_attr(attrs, name_table, "mixed")?;
1173        let mixed_explicit = mixed_opt.is_some();
1174        let mixed = mixed_opt.unwrap_or(false);
1175
1176        Ok(Self {
1177            id,
1178            mixed,
1179            mixed_explicit,
1180            base_type: None,
1181            derivation: None,
1182            particle: None,
1183            open_content: None,
1184            attributes: Vec::new(),
1185            attribute_groups: Vec::new(),
1186            attribute_wildcard: None,
1187            assertions: Vec::new(),
1188            derivation_id: None,
1189            annotation: None,
1190            source,
1191            foreign_attributes: Vec::new(),
1192            derivation_seen: false,
1193        })
1194    }
1195}
1196
1197impl Frame for ComplexContentFrame {
1198    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
1199        if self.derivation_seen {
1200            return false;
1201        }
1202        matches!(
1203            local_name,
1204            xsd_names::ANNOTATION | xsd_names::RESTRICTION | xsd_names::EXTENSION
1205        )
1206    }
1207
1208    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
1209        matches!(local_name, "id" | "mixed")
1210    }
1211
1212    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
1213        if matches!(local_name, xsd_names::RESTRICTION | xsd_names::EXTENSION) {
1214            self.derivation_seen = true;
1215        }
1216    }
1217
1218    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
1219        match child {
1220            FrameResult::Annotation(ann) => {
1221                self.annotation = Some(ann);
1222            }
1223            FrameResult::Restriction(res) => {
1224                self.base_type = res.base_type.clone();
1225                self.derivation = Some(DerivationMethod::Restriction);
1226                self.particle = res.particle.clone();
1227                self.open_content = res.open_content.clone();
1228                self.attributes = res.attributes.clone();
1229                self.attribute_groups = res.attribute_groups.clone();
1230                self.attribute_wildcard = res.attribute_wildcard.clone();
1231                self.assertions = res.assertions.clone();
1232                self.derivation_id = res.id.clone();
1233            }
1234            FrameResult::Extension(res) => {
1235                self.base_type = res.base_type;
1236                self.derivation = Some(DerivationMethod::Extension);
1237                self.particle = res.particle;
1238                self.open_content = res.open_content;
1239                self.attributes = res.attributes;
1240                self.attribute_groups = res.attribute_groups;
1241                self.attribute_wildcard = res.attribute_wildcard;
1242                self.assertions = res.assertions;
1243                self.derivation_id = res.id;
1244            }
1245            FrameResult::Skip => {}
1246            _ => {}
1247        }
1248        Ok(())
1249    }
1250
1251    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
1252        // src-ct: the XML content model of <xs:complexContent> requires exactly
1253        // one of <xs:restriction> or <xs:extension> as a child (plus an optional
1254        // leading annotation). An empty <xs:complexContent> or one containing
1255        // only an annotation is a content-model violation.
1256        let derivation = self.derivation.ok_or_else(|| SchemaError::structural(
1257            "src-ct",
1258            "xs:complexContent requires an xs:restriction or xs:extension child",
1259            None,
1260        ))?;
1261        Ok(FrameResult::ComplexContent(ComplexContentDefResult {
1262            particle: self.particle,
1263            derivation,
1264            mixed: self.mixed,
1265            mixed_explicit: self.mixed_explicit,
1266            base_type: self.base_type,
1267            open_content: self.open_content,
1268            attributes: self.attributes,
1269            attribute_groups: self.attribute_groups,
1270            attribute_wildcard: self.attribute_wildcard,
1271            assertions: self.assertions,
1272            id: self.id,
1273            derivation_id: self.derivation_id,
1274            source: self.source,
1275        }))
1276    }
1277
1278    fn has_annotation(&self) -> bool {
1279        self.annotation.is_some()
1280    }
1281
1282    fn source(&self) -> Option<&SourceRef> {
1283        self.source.as_ref()
1284    }
1285
1286    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
1287        self.foreign_attributes = attrs;
1288    }
1289}
1290
1291// ============================================================================
1292// Complex Type Frame
1293// ============================================================================
1294
1295/// Parsing phase for complexType
1296#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1297enum ComplexTypePhase {
1298    Annotation,
1299    Content,
1300    Attributes,
1301    Done,
1302}
1303
1304/// Frame for xs:complexType element
1305pub struct ComplexTypeFrame {
1306    phase: ComplexTypePhase,
1307    name: Option<NameId>,
1308    base_type: Option<TypeRefResult>,
1309    derivation_method: Option<DerivationMethod>,
1310    mixed: bool,
1311    /// `true` when the `<xs:complexType mixed="…">` attribute was explicitly
1312    /// present. Used by §3.4.2.3 step 1 to require that an explicit
1313    /// `<complexContent mixed="…">` agree with this value.
1314    mixed_explicit: bool,
1315    is_abstract: bool,
1316    final_derivation: Option<DerivationSet>,
1317    block: Option<DerivationSet>,
1318    default_attributes_apply: bool,
1319    id: Option<String>,
1320    content: ComplexContentResult,
1321    open_content: Option<OpenContentResult>,
1322    attributes: Vec<AttributeUseResult>,
1323    attribute_groups: Vec<QNameRef>,
1324    attribute_wildcard: Option<WildcardResult>,
1325    assertions: Vec<AssertResult>,
1326    #[cfg(feature = "xsd11")]
1327    xpath_default_namespace: Option<String>,
1328    annotation: Option<Annotation>,
1329    source: Option<SourceRef>,
1330    foreign_attributes: Vec<ForeignAttribute>,
1331}
1332
1333impl ComplexTypeFrame {
1334    pub fn new(
1335        attrs: &AttributeMap,
1336        name_table: &NameTable,
1337        source: Option<SourceRef>,
1338    ) -> SchemaResult<Self> {
1339        let name = attrs
1340            .get_value_by_name(name_table, "name")
1341            .and_then(|s| name_table.get(s));
1342
1343        let mixed_opt = parse_optional_bool_attr(attrs, name_table, "mixed")?;
1344        let mixed_explicit = mixed_opt.is_some();
1345        let mixed = mixed_opt.unwrap_or(false);
1346
1347        let is_abstract = parse_bool_attr_default(attrs, name_table, "abstract", false)?;
1348
1349        let final_derivation = parse_derivation_set_opt(
1350            attrs.get_value_by_name(name_table, "final"),
1351        )?;
1352
1353        let block = parse_derivation_set_opt(
1354            attrs.get_value_by_name(name_table, "block"),
1355        )?;
1356
1357        let default_attributes_apply =
1358            parse_bool_attr_default(attrs, name_table, "defaultAttributesApply", true)?;
1359
1360        let id = attrs
1361            .get_value_by_name(name_table, "id")
1362            .map(String::from);
1363
1364        #[cfg(feature = "xsd11")]
1365        let xpath_default_namespace = attrs
1366            .get_value_by_name(name_table, "xpathDefaultNamespace")
1367            .map(String::from);
1368
1369        Ok(Self {
1370            phase: ComplexTypePhase::Annotation,
1371            name,
1372            base_type: None,
1373            derivation_method: None,
1374            mixed,
1375            mixed_explicit,
1376            is_abstract,
1377            final_derivation,
1378            block,
1379            default_attributes_apply,
1380            id,
1381            content: ComplexContentResult::Empty,
1382            open_content: None,
1383            attributes: Vec::new(),
1384            attribute_groups: Vec::new(),
1385            attribute_wildcard: None,
1386            assertions: Vec::new(),
1387            #[cfg(feature = "xsd11")]
1388            xpath_default_namespace,
1389            annotation: None,
1390            source,
1391            foreign_attributes: Vec::new(),
1392        })
1393    }
1394}
1395
1396impl Frame for ComplexTypeFrame {
1397    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
1398        #[cfg(feature = "xsd11")]
1399        let is_xsd11_element = matches!(
1400            local_name,
1401            xsd_names::OPEN_CONTENT | xsd_names::ASSERT
1402        );
1403        #[cfg(not(feature = "xsd11"))]
1404        let is_xsd11_element = false;
1405
1406        match self.phase {
1407            ComplexTypePhase::Annotation => matches!(
1408                local_name,
1409                xsd_names::ANNOTATION
1410                    | xsd_names::SIMPLE_CONTENT
1411                    | xsd_names::COMPLEX_CONTENT
1412                    | xsd_names::SEQUENCE
1413                    | xsd_names::CHOICE
1414                    | xsd_names::ALL
1415                    | xsd_names::GROUP
1416                    | xsd_names::ATTRIBUTE
1417                    | xsd_names::ATTRIBUTE_GROUP
1418                    | xsd_names::ANY_ATTRIBUTE
1419            ) || is_xsd11_element,
1420            ComplexTypePhase::Content => matches!(
1421                local_name,
1422                xsd_names::SIMPLE_CONTENT
1423                    | xsd_names::COMPLEX_CONTENT
1424                    | xsd_names::SEQUENCE
1425                    | xsd_names::CHOICE
1426                    | xsd_names::ALL
1427                    | xsd_names::GROUP
1428                    | xsd_names::ATTRIBUTE
1429                    | xsd_names::ATTRIBUTE_GROUP
1430                    | xsd_names::ANY_ATTRIBUTE
1431            ) || is_xsd11_element,
1432            ComplexTypePhase::Attributes => matches!(
1433                local_name,
1434                xsd_names::ATTRIBUTE
1435                    | xsd_names::ATTRIBUTE_GROUP
1436                    | xsd_names::ANY_ATTRIBUTE
1437            ) || is_xsd11_element,
1438            ComplexTypePhase::Done => false,
1439        }
1440    }
1441
1442    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
1443        #[cfg(feature = "xsd11")]
1444        if local_name == "xpathDefaultNamespace" {
1445            return true;
1446        }
1447        matches!(
1448            local_name,
1449            "name"
1450                | "mixed"
1451                | "abstract"
1452                | "final"
1453                | "block"
1454                | "defaultAttributesApply"
1455                | "id"
1456        )
1457    }
1458
1459    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
1460        match local_name {
1461            xsd_names::ANNOTATION => {
1462                self.phase = ComplexTypePhase::Content;
1463            }
1464            xsd_names::SIMPLE_CONTENT | xsd_names::COMPLEX_CONTENT => {
1465                self.phase = ComplexTypePhase::Done;
1466            }
1467            xsd_names::SEQUENCE | xsd_names::CHOICE | xsd_names::ALL | xsd_names::GROUP => {
1468                self.phase = ComplexTypePhase::Attributes;
1469            }
1470            xsd_names::ATTRIBUTE | xsd_names::ATTRIBUTE_GROUP => {
1471                self.phase = ComplexTypePhase::Attributes;
1472            }
1473            xsd_names::ANY_ATTRIBUTE => {
1474                self.phase = ComplexTypePhase::Done;
1475            }
1476            _ => {}
1477        }
1478    }
1479
1480    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
1481        match child {
1482            FrameResult::Annotation(ann) => {
1483                self.annotation = Some(ann);
1484            }
1485            FrameResult::OpenContent(open_content) => {
1486                self.open_content = Some(open_content);
1487            }
1488            FrameResult::SimpleContent(mut sc) => {
1489                self.base_type = sc
1490                    .base_type
1491                    .as_ref()
1492                    .and_then(|bt| match bt {
1493                        TypeRefResult::QName(qname) => {
1494                            Some(TypeRefResult::QName(qname.clone()))
1495                        }
1496                        _ => None,
1497                    });
1498                self.derivation_method = Some(sc.derivation);
1499                self.attributes = std::mem::take(&mut sc.attributes);
1500                self.attribute_groups = std::mem::take(&mut sc.attribute_groups);
1501                self.attribute_wildcard = sc.attribute_wildcard.take();
1502                self.content = ComplexContentResult::Simple(sc);
1503            }
1504            FrameResult::ComplexContent(mut cc) => {
1505                self.base_type = cc
1506                    .base_type
1507                    .as_ref()
1508                    .and_then(|bt| match bt {
1509                        TypeRefResult::QName(qname) => {
1510                            Some(TypeRefResult::QName(qname.clone()))
1511                        }
1512                        _ => None,
1513                    });
1514                self.derivation_method = Some(cc.derivation);
1515                self.attributes = std::mem::take(&mut cc.attributes);
1516                self.attribute_groups = std::mem::take(&mut cc.attribute_groups);
1517                self.attribute_wildcard = cc.attribute_wildcard.take();
1518                // §3.4.2.3 step 1: `<complexContent mixed=…>` (clause 1.1) and
1519                // `<complexType mixed=…>` (clause 1.2) must agree when both are
1520                // explicit. The note at the end of step 1 says these "will never
1521                // contradict each other in a conforming schema document".
1522                if cc.mixed_explicit && self.mixed_explicit && cc.mixed != self.mixed {
1523                    return Err(SchemaError::structural(
1524                        "src-ct",
1525                        "<complexType mixed=…> and <complexContent mixed=…> are both \
1526                         present but disagree (§3.4.2.3 step 1)",
1527                        None,
1528                    ));
1529                }
1530                if cc.mixed_explicit {
1531                    self.mixed = cc.mixed;
1532                } else {
1533                    cc.mixed = self.mixed;
1534                }
1535                self.content = ComplexContentResult::Complex(cc);
1536            }
1537            FrameResult::Particle(particle) => {
1538                self.content = ComplexContentResult::Complex(ComplexContentDefResult {
1539                    particle: Some(particle),
1540                    derivation: DerivationMethod::Restriction,
1541                    mixed: self.mixed,
1542                    mixed_explicit: true,
1543                    base_type: None,
1544                    open_content: None,
1545                    attributes: Vec::new(),
1546                    attribute_groups: Vec::new(),
1547                    attribute_wildcard: None,
1548                    assertions: Vec::new(),
1549                    id: None,
1550                    derivation_id: None,
1551                    source: None,
1552                });
1553            }
1554            FrameResult::Attribute(attr) => {
1555                let use_kind = match attr.use_kind.as_deref() {
1556                    Some("required") => AttributeUseKind::Required,
1557                    Some("prohibited") => AttributeUseKind::Prohibited,
1558                    _ => AttributeUseKind::Optional,
1559                };
1560                self.attributes.push(AttributeUseResult {
1561                    attribute: attr,
1562                    use_kind,
1563                });
1564            }
1565            FrameResult::Group(GroupFrameResult::Model(mg)) => {
1566                let min_occurs = mg.min_occurs;
1567                let max_occurs = mg.max_occurs;
1568                let particle = ParticleResult {
1569                    term: ParticleTerm::Group(*mg),
1570                    min_occurs,
1571                    max_occurs,
1572                    source: None,
1573                };
1574                self.content = ComplexContentResult::Complex(ComplexContentDefResult {
1575                    particle: Some(particle),
1576                    derivation: DerivationMethod::Restriction,
1577                    mixed: self.mixed,
1578                    mixed_explicit: true,
1579                    base_type: None,
1580                    open_content: None,
1581                    attributes: Vec::new(),
1582                    attribute_groups: Vec::new(),
1583                    attribute_wildcard: None,
1584                    assertions: Vec::new(),
1585                    id: None,
1586                    derivation_id: None,
1587                    source: None,
1588                });
1589            }
1590            FrameResult::Group(GroupFrameResult::Attribute(ag)) => {
1591                if let Some(ref_name) = ag.ref_name {
1592                    self.attribute_groups.push(ref_name);
1593                }
1594            }
1595            FrameResult::Wildcard(wc) => {
1596                self.attribute_wildcard = Some(wc);
1597            }
1598            FrameResult::Assert(assertion) => {
1599                self.assertions.push(assertion);
1600            }
1601            FrameResult::Skip => {}
1602            _ => {}
1603        }
1604        Ok(())
1605    }
1606
1607    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
1608        let mut content = self.content;
1609        match &mut content {
1610            ComplexContentResult::Empty => {
1611                if self.open_content.is_some() || !self.assertions.is_empty() {
1612                    content = ComplexContentResult::Complex(ComplexContentDefResult {
1613                        particle: None,
1614                        derivation: DerivationMethod::Restriction,
1615                        mixed: self.mixed,
1616                        mixed_explicit: true,
1617                        base_type: None,
1618                        open_content: self.open_content,
1619                        attributes: Vec::new(),
1620                        attribute_groups: Vec::new(),
1621                        attribute_wildcard: None,
1622                        assertions: self.assertions,
1623                        id: None,
1624                        derivation_id: None,
1625                        source: None,
1626                    });
1627                }
1628            }
1629            ComplexContentResult::Complex(cc) => {
1630                if cc.open_content.is_none() {
1631                    cc.open_content = self.open_content;
1632                }
1633                if !self.assertions.is_empty() {
1634                    cc.assertions.extend(self.assertions);
1635                }
1636            }
1637            ComplexContentResult::Simple(_) => {}
1638        }
1639
1640        let annotation = merge_foreign_attributes(
1641            self.annotation,
1642            self.foreign_attributes,
1643            self.source.clone(),
1644        );
1645        Ok(FrameResult::Type(TypeFrameResult::Complex(Box::new(ComplexTypeResult {
1646            name: self.name,
1647            base_type: self.base_type,
1648            derivation_method: self.derivation_method,
1649            content,
1650            attributes: self.attributes,
1651            attribute_groups: self.attribute_groups,
1652            attribute_wildcard: self.attribute_wildcard,
1653            mixed: self.mixed,
1654            is_abstract: self.is_abstract,
1655            final_derivation: self.final_derivation,
1656            block: self.block,
1657            default_attributes_apply: self.default_attributes_apply,
1658            id: self.id,
1659            #[cfg(feature = "xsd11")]
1660            xpath_default_namespace: self.xpath_default_namespace,
1661            annotation,
1662            source: self.source,
1663        }))))
1664    }
1665
1666    fn has_annotation(&self) -> bool {
1667        self.annotation.is_some()
1668    }
1669
1670    fn source(&self) -> Option<&SourceRef> {
1671        self.source.as_ref()
1672    }
1673
1674    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
1675        self.foreign_attributes = attrs;
1676    }
1677
1678    fn children_inside_complex_type(&self) -> bool {
1679        true
1680    }
1681}
1682