Skip to main content

xsd_schema/parser/frames/
elements.rs

1// ============================================================================
2// Element Frame
3// ============================================================================
4
5/// Parsing phase for element
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[allow(dead_code)]
8enum ElementPhase {
9    Annotation,
10    Type,
11    Identity,
12    Done,
13}
14
15/// Frame for xs:element
16pub struct ElementFrame {
17    phase: ElementPhase,
18    name: Option<NameId>,
19    ref_name: Option<QNameRef>,
20    target_namespace: Option<NameId>,
21    type_ref: Option<TypeRefResult>,
22    inline_type: Option<Box<TypeFrameResult>>,
23    substitution_group: Vec<QNameRef>,
24    default_value: Option<String>,
25    fixed_value: Option<String>,
26    nillable: bool,
27    is_abstract: bool,
28    min_occurs: u32,
29    max_occurs: Option<u32>,
30    block: Option<DerivationSet>,
31    final_derivation: Option<DerivationSet>,
32    form: Option<String>,
33    id: Option<String>,
34    alternatives: Vec<AlternativeResult>,
35    identity_constraints: Vec<IdentityResult>,
36    /// XSD 1.1: pending identity constraint references (@ref)
37    identity_constraint_refs: Vec<IdentityRefResult>,
38    annotation: Option<Annotation>,
39    source: Option<SourceRef>,
40    foreign_attributes: Vec<ForeignAttribute>,
41}
42
43impl ElementFrame {
44    pub fn new(
45        attrs: &AttributeMap,
46        name_table: &NameTable,
47        source: Option<SourceRef>,
48        ns_snapshot: &NamespaceContextSnapshot,
49    ) -> SchemaResult<Self> {
50        let name = attrs
51            .get_value_by_name(name_table, "name")
52            .and_then(|s| name_table.get(s));
53
54        let ref_name = attrs
55            .get_value_by_name(name_table, "ref")
56            .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
57            .transpose()?;
58
59        let target_namespace = attrs
60            .get_value_by_name(name_table, "targetNamespace")
61            .map(|s| name_table.add(s));
62
63        let type_ref = attrs
64            .get_value_by_name(name_table, "type")
65            .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
66            .transpose()?
67            .map(TypeRefResult::QName);
68
69        let substitution_group = attrs
70            .get_value_by_name(name_table, "substitutionGroup")
71            .map(|s| parse_qname_list(s, name_table, ns_snapshot))
72            .transpose()?
73            .unwrap_or_default();
74
75        let default_value = attrs
76            .get_value_by_name(name_table, "default")
77            .map(String::from);
78
79        let fixed_value = attrs
80            .get_value_by_name(name_table, "fixed")
81            .map(String::from);
82
83        let nillable = parse_bool_attr_default(attrs, name_table, "nillable", false)?;
84
85        let is_abstract = parse_bool_attr_default(attrs, name_table, "abstract", false)?;
86
87        let min_occurs = parse_min_occurs_attr(attrs, name_table, "minOccurs")?;
88
89        let max_occurs = parse_max_occurs_attr(attrs, name_table, "maxOccurs")?;
90
91        let block = parse_derivation_set_opt(
92            attrs.get_value_by_name(name_table, "block"),
93        )?;
94
95        let final_derivation = parse_derivation_set_opt(
96            attrs.get_value_by_name(name_table, "final"),
97        )?;
98
99        let form = attrs
100            .get_value_by_name(name_table, "form")
101            .map(String::from);
102
103        let id = attrs
104            .get_value_by_name(name_table, "id")
105            .map(String::from);
106
107        Ok(Self {
108            phase: ElementPhase::Annotation,
109            name,
110            ref_name,
111            target_namespace,
112            type_ref,
113            inline_type: None,
114            substitution_group,
115            default_value,
116            fixed_value,
117            nillable,
118            is_abstract,
119            min_occurs,
120            max_occurs,
121            block,
122            final_derivation,
123            form,
124            id,
125            alternatives: Vec::new(),
126            identity_constraints: Vec::new(),
127            identity_constraint_refs: Vec::new(),
128            annotation: None,
129            source,
130            foreign_attributes: Vec::new(),
131        })
132    }
133}
134
135impl Frame for ElementFrame {
136    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
137        #[cfg(feature = "xsd11")]
138        let is_xsd11_element = matches!(local_name, xsd_names::ALTERNATIVE);
139        #[cfg(not(feature = "xsd11"))]
140        let is_xsd11_element = false;
141
142        // src-element clause 3: when `ref` is present, only annotation is allowed
143        // (no inline simpleType/complexType, no identity constraints).
144        if self.ref_name.is_some() {
145            return local_name == xsd_names::ANNOTATION
146                && self.phase == ElementPhase::Annotation;
147        }
148
149        match self.phase {
150            ElementPhase::Annotation => matches!(
151                local_name,
152                xsd_names::ANNOTATION
153                    | xsd_names::SIMPLE_TYPE
154                    | xsd_names::COMPLEX_TYPE
155                    | xsd_names::KEY
156                    | xsd_names::KEYREF
157                    | xsd_names::UNIQUE
158            ) || is_xsd11_element,
159            ElementPhase::Type => matches!(
160                local_name,
161                xsd_names::SIMPLE_TYPE
162                    | xsd_names::COMPLEX_TYPE
163                    | xsd_names::KEY
164                    | xsd_names::KEYREF
165                    | xsd_names::UNIQUE
166            ) || is_xsd11_element,
167            ElementPhase::Identity => {
168                matches!(
169                    local_name,
170                    xsd_names::KEY | xsd_names::KEYREF | xsd_names::UNIQUE
171                ) || is_xsd11_element
172            }
173            ElementPhase::Done => false,
174        }
175    }
176
177    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
178        matches!(
179            local_name,
180            "name"
181                | "ref"
182                | "targetNamespace"
183                | "type"
184                | "substitutionGroup"
185                | "default"
186                | "fixed"
187                | "nillable"
188                | "abstract"
189                | "minOccurs"
190                | "maxOccurs"
191                | "block"
192                | "final"
193                | "form"
194                | "id"
195        )
196    }
197
198    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
199        match local_name {
200            xsd_names::ANNOTATION => {
201                self.phase = ElementPhase::Type;
202            }
203            xsd_names::SIMPLE_TYPE | xsd_names::COMPLEX_TYPE => {
204                self.phase = ElementPhase::Identity;
205            }
206            xsd_names::ALTERNATIVE => {
207                self.phase = ElementPhase::Identity;
208            }
209            xsd_names::KEY | xsd_names::KEYREF | xsd_names::UNIQUE => {
210                self.phase = ElementPhase::Identity;
211            }
212            _ => {}
213        }
214    }
215
216    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
217        match child {
218            FrameResult::Annotation(ann) => {
219                self.annotation = Some(ann);
220            }
221            FrameResult::Type(t) => {
222                self.inline_type = Some(Box::new(t));
223            }
224            FrameResult::Alternative(alt) => {
225                self.alternatives.push(alt);
226            }
227            FrameResult::Identity(ic) => {
228                self.identity_constraints.push(ic);
229            }
230            FrameResult::IdentityRef(ic_ref) => {
231                self.identity_constraint_refs.push(ic_ref);
232            }
233            FrameResult::Skip => {}
234            _ => {}
235        }
236        Ok(())
237    }
238
239    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
240        // src-element.1: type and inline type are mutually exclusive
241        if self.type_ref.is_some() && self.inline_type.is_some() {
242            return Err(SchemaError::structural(
243                "src-element",
244                "Element cannot have both 'type' attribute and inline type definition",
245                None,
246            ));
247        }
248
249        let annotation = merge_foreign_attributes(
250            self.annotation,
251            self.foreign_attributes,
252            self.source.clone(),
253        );
254        Ok(FrameResult::Element(ElementFrameResult {
255            name: self.name,
256            ref_name: self.ref_name,
257            target_namespace: self.target_namespace,
258            type_ref: self.type_ref,
259            inline_type: self.inline_type,
260            substitution_group: self.substitution_group,
261            default_value: self.default_value,
262            fixed_value: self.fixed_value,
263            nillable: self.nillable,
264            is_abstract: self.is_abstract,
265            min_occurs: self.min_occurs,
266            max_occurs: self.max_occurs,
267            block: self.block,
268            final_derivation: self.final_derivation,
269            form: self.form,
270            id: self.id,
271            alternatives: self.alternatives,
272            identity_constraints: self.identity_constraints,
273            identity_constraint_refs: self.identity_constraint_refs,
274            annotation,
275            source: self.source,
276        }))
277    }
278
279    fn has_annotation(&self) -> bool {
280        self.annotation.is_some()
281    }
282
283    fn source(&self) -> Option<&SourceRef> {
284        self.source.as_ref()
285    }
286
287    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
288        self.foreign_attributes = attrs;
289    }
290}
291
292// ============================================================================
293// Attribute Frame
294// ============================================================================
295
296/// Frame for xs:attribute
297pub struct AttributeFrame {
298    name: Option<NameId>,
299    ref_name: Option<QNameRef>,
300    target_namespace: Option<NameId>,
301    type_ref: Option<TypeRefResult>,
302    inline_type: Option<Box<SimpleTypeResult>>,
303    default_value: Option<String>,
304    fixed_value: Option<String>,
305    use_kind: Option<String>,
306    form: Option<String>,
307    inheritable: bool,
308    id: Option<String>,
309    annotation: Option<Annotation>,
310    /// True once a non-annotation child has been seen — annotation must come first.
311    past_annotation: bool,
312    source: Option<SourceRef>,
313    foreign_attributes: Vec<ForeignAttribute>,
314}
315
316impl AttributeFrame {
317    pub fn new(
318        attrs: &AttributeMap,
319        name_table: &NameTable,
320        source: Option<SourceRef>,
321        ns_snapshot: &NamespaceContextSnapshot,
322    ) -> SchemaResult<Self> {
323        let name = attrs
324            .get_value_by_name(name_table, "name")
325            .and_then(|s| name_table.get(s));
326
327        let ref_name = attrs
328            .get_value_by_name(name_table, "ref")
329            .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
330            .transpose()?;
331
332        let target_namespace = attrs
333            .get_value_by_name(name_table, "targetNamespace")
334            .map(|s| name_table.add(s));
335
336        let type_ref = attrs
337            .get_value_by_name(name_table, "type")
338            .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
339            .transpose()?
340            .map(TypeRefResult::QName);
341
342        let default_value = attrs
343            .get_value_by_name(name_table, "default")
344            .map(String::from);
345
346        let fixed_value = attrs
347            .get_value_by_name(name_table, "fixed")
348            .map(String::from);
349
350        validate_attr_value(attrs, name_table, "use", parse_use)?;
351        let use_kind = attrs
352            .get_value_by_name(name_table, "use")
353            .map(String::from);
354
355        validate_attr_value(attrs, name_table, "form", parse_form)?;
356        let form = attrs
357            .get_value_by_name(name_table, "form")
358            .map(String::from);
359
360        let inheritable = parse_bool_attr_default(attrs, name_table, "inheritable", false)?;
361
362        let id = attrs
363            .get_value_by_name(name_table, "id")
364            .map(String::from);
365
366        Ok(Self {
367            name,
368            ref_name,
369            target_namespace,
370            type_ref,
371            inline_type: None,
372            default_value,
373            fixed_value,
374            use_kind,
375            form,
376            inheritable,
377            id,
378            annotation: None,
379            past_annotation: false,
380            source,
381            foreign_attributes: Vec::new(),
382        })
383    }
384}
385
386impl Frame for AttributeFrame {
387    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
388        // Annotation must precede the inline simpleType; only one inline
389        // simpleType is permitted (xs:attribute content model:
390        // (annotation?, simpleType?)).
391        if local_name == xsd_names::ANNOTATION && self.past_annotation {
392            return false;
393        }
394        if local_name == xsd_names::SIMPLE_TYPE && self.inline_type.is_some() {
395            return false;
396        }
397        matches!(local_name, xsd_names::ANNOTATION | xsd_names::SIMPLE_TYPE)
398    }
399
400    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
401        matches!(
402            local_name,
403            "name"
404                | "ref"
405                | "targetNamespace"
406                | "type"
407                | "default"
408                | "fixed"
409                | "use"
410                | "form"
411                | "inheritable"
412                | "id"
413        )
414    }
415
416    fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
417        if local_name != xsd_names::ANNOTATION {
418            self.past_annotation = true;
419        }
420    }
421
422    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
423        match child {
424            FrameResult::Annotation(ann) => {
425                self.annotation = Some(ann);
426            }
427            FrameResult::Type(TypeFrameResult::Simple(st)) => {
428                self.inline_type = Some(st);
429            }
430            FrameResult::Skip => {}
431            _ => {}
432        }
433        Ok(())
434    }
435
436    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
437        // src-attribute.3.2: ref + <simpleType> are mutually exclusive
438        if self.ref_name.is_some() && self.inline_type.is_some() {
439            return Err(SchemaError::structural(
440                "src-attribute",
441                "Attribute reference cannot have inline simpleType",
442                None,
443            ));
444        }
445        // src-attribute.4: type and inline simpleType are mutually exclusive
446        if self.type_ref.is_some() && self.inline_type.is_some() {
447            return Err(SchemaError::structural(
448                "src-attribute",
449                "Attribute cannot have both 'type' attribute and inline simpleType",
450                None,
451            ));
452        }
453
454        let annotation = merge_foreign_attributes(
455            self.annotation,
456            self.foreign_attributes,
457            self.source.clone(),
458        );
459        Ok(FrameResult::Attribute(AttributeFrameResult {
460            name: self.name,
461            ref_name: self.ref_name,
462            target_namespace: self.target_namespace,
463            type_ref: self.type_ref,
464            inline_type: self.inline_type,
465            default_value: self.default_value,
466            fixed_value: self.fixed_value,
467            use_kind: self.use_kind,
468            form: self.form,
469            inheritable: self.inheritable,
470            id: self.id,
471            annotation,
472            source: self.source,
473        }))
474    }
475
476    fn has_annotation(&self) -> bool {
477        self.annotation.is_some()
478    }
479
480    fn source(&self) -> Option<&SourceRef> {
481        self.source.as_ref()
482    }
483
484    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
485        self.foreign_attributes = attrs;
486    }
487}
488