Skip to main content

xsd_schema/parser/frames/
wildcards.rs

1// ============================================================================
2// Wildcard Frames (any, anyAttribute)
3// ============================================================================
4
5/// Frame for xs:any
6pub struct AnyFrame {
7    namespace: WildcardNamespace,
8    process_contents: ProcessContents,
9    not_namespace: Vec<NamespaceToken>,
10    not_qname: Vec<NotQNameItem>,
11    min_occurs: u32,
12    max_occurs: Option<u32>,
13    id: Option<String>,
14    annotation: Option<Annotation>,
15    source: Option<SourceRef>,
16    foreign_attributes: Vec<ForeignAttribute>,
17}
18
19impl AnyFrame {
20    pub fn new(
21        attrs: &AttributeMap,
22        name_table: &NameTable,
23        source: Option<SourceRef>,
24        #[cfg(feature = "xsd11")] ns_snapshot: &NamespaceContextSnapshot,
25    ) -> SchemaResult<Self> {
26        let has_namespace = attrs.get_value_by_name(name_table, "namespace").is_some();
27        let has_not_namespace = attrs.get_value_by_name(name_table, "notNamespace").is_some();
28
29        #[cfg(feature = "xsd11")]
30        if has_namespace && has_not_namespace {
31            return Err(SchemaError::structural(
32                "src-wildcard",
33                "Attributes 'namespace' and 'notNamespace' are mutually exclusive on xs:any".to_string(),
34                None,
35            ));
36        }
37
38        let namespace = parse_namespace_constraint(
39            attrs.get_value_by_name(name_table, "namespace"),
40            name_table,
41        )?;
42
43        let process_contents =
44            parse_process_contents_attr(attrs, name_table, "processContents")?;
45
46        #[cfg(feature = "xsd11")]
47        let not_namespace = parse_not_namespace(
48            attrs.get_value_by_name(name_table, "notNamespace"),
49            name_table,
50        );
51        #[cfg(not(feature = "xsd11"))]
52        let not_namespace = {
53            let _ = has_namespace;
54            let _ = has_not_namespace;
55            Vec::new()
56        };
57
58        #[cfg(feature = "xsd11")]
59        let not_qname = parse_not_qname(
60            attrs.get_value_by_name(name_table, "notQName"),
61            name_table,
62            ns_snapshot,
63            true, // is_element_wildcard
64        )?;
65        #[cfg(not(feature = "xsd11"))]
66        let not_qname = Vec::new();
67
68        let min_occurs = parse_min_occurs_attr(attrs, name_table, "minOccurs")?;
69
70        let max_occurs = parse_max_occurs_attr(attrs, name_table, "maxOccurs")?;
71
72        let id = attrs
73            .get_value_by_name(name_table, "id")
74            .map(String::from);
75
76        Ok(Self {
77            namespace,
78            process_contents,
79            not_namespace,
80            not_qname,
81            min_occurs,
82            max_occurs,
83            id,
84            annotation: None,
85            source,
86            foreign_attributes: Vec::new(),
87        })
88    }
89}
90
91impl Frame for AnyFrame {
92    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
93        matches!(local_name, xsd_names::ANNOTATION)
94    }
95
96    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
97        matches!(
98            local_name,
99            "namespace"
100                | "processContents"
101                | "notNamespace"
102                | "notQName"
103                | "minOccurs"
104                | "maxOccurs"
105                | "id"
106        )
107    }
108
109    fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {}
110
111    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
112        if let FrameResult::Annotation(ann) = child {
113            self.annotation = Some(ann);
114        }
115        Ok(())
116    }
117
118    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
119        let annotation = merge_foreign_attributes(
120            self.annotation,
121            self.foreign_attributes,
122            self.source.clone(),
123        );
124        Ok(FrameResult::Particle(ParticleResult {
125            term: ParticleTerm::Any(WildcardResult {
126                namespace: self.namespace,
127                process_contents: self.process_contents,
128                not_namespace: self.not_namespace,
129                not_qname: self.not_qname,
130                id: self.id,
131                annotation,
132                source: self.source.clone(),
133            }),
134            min_occurs: self.min_occurs,
135            max_occurs: self.max_occurs,
136            source: self.source,
137        }))
138    }
139
140    fn has_annotation(&self) -> bool {
141        self.annotation.is_some()
142    }
143
144    fn source(&self) -> Option<&SourceRef> {
145        self.source.as_ref()
146    }
147
148    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
149        self.foreign_attributes = attrs;
150    }
151}
152
153/// Frame for xs:anyAttribute
154pub struct AnyAttributeFrame {
155    namespace: WildcardNamespace,
156    process_contents: ProcessContents,
157    not_namespace: Vec<NamespaceToken>,
158    not_qname: Vec<NotQNameItem>,
159    id: Option<String>,
160    annotation: Option<Annotation>,
161    source: Option<SourceRef>,
162    foreign_attributes: Vec<ForeignAttribute>,
163}
164
165impl AnyAttributeFrame {
166    pub fn new(
167        attrs: &AttributeMap,
168        name_table: &NameTable,
169        source: Option<SourceRef>,
170        #[cfg(feature = "xsd11")] ns_snapshot: &NamespaceContextSnapshot,
171    ) -> SchemaResult<Self> {
172        let has_namespace = attrs.get_value_by_name(name_table, "namespace").is_some();
173        let has_not_namespace = attrs.get_value_by_name(name_table, "notNamespace").is_some();
174
175        #[cfg(feature = "xsd11")]
176        if has_namespace && has_not_namespace {
177            return Err(SchemaError::structural(
178                "src-wildcard",
179                "Attributes 'namespace' and 'notNamespace' are mutually exclusive on xs:anyAttribute".to_string(),
180                None,
181            ));
182        }
183
184        let namespace = parse_namespace_constraint(
185            attrs.get_value_by_name(name_table, "namespace"),
186            name_table,
187        )?;
188
189        let process_contents =
190            parse_process_contents_attr(attrs, name_table, "processContents")?;
191
192        #[cfg(feature = "xsd11")]
193        let not_namespace = parse_not_namespace(
194            attrs.get_value_by_name(name_table, "notNamespace"),
195            name_table,
196        );
197        #[cfg(not(feature = "xsd11"))]
198        let not_namespace = {
199            let _ = has_namespace;
200            let _ = has_not_namespace;
201            Vec::new()
202        };
203
204        #[cfg(feature = "xsd11")]
205        let not_qname = parse_not_qname(
206            attrs.get_value_by_name(name_table, "notQName"),
207            name_table,
208            ns_snapshot,
209            false, // is_element_wildcard = false (attribute wildcard)
210        )?;
211        #[cfg(not(feature = "xsd11"))]
212        let not_qname = Vec::new();
213
214        let id = attrs
215            .get_value_by_name(name_table, "id")
216            .map(String::from);
217
218        Ok(Self {
219            namespace,
220            process_contents,
221            not_namespace,
222            not_qname,
223            id,
224            annotation: None,
225            source,
226            foreign_attributes: Vec::new(),
227        })
228    }
229}
230
231impl Frame for AnyAttributeFrame {
232    fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
233        matches!(local_name, xsd_names::ANNOTATION)
234    }
235
236    fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
237        matches!(
238            local_name,
239            "namespace" | "processContents" | "notNamespace" | "notQName" | "id"
240        )
241    }
242
243    fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {}
244
245    fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
246        if let FrameResult::Annotation(ann) = child {
247            self.annotation = Some(ann);
248        }
249        Ok(())
250    }
251
252    fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
253        let annotation = merge_foreign_attributes(
254            self.annotation,
255            self.foreign_attributes,
256            self.source.clone(),
257        );
258        Ok(FrameResult::Wildcard(WildcardResult {
259            namespace: self.namespace,
260            process_contents: self.process_contents,
261            not_namespace: self.not_namespace,
262            not_qname: self.not_qname,
263            id: self.id,
264            annotation,
265            source: self.source,
266        }))
267    }
268
269    fn has_annotation(&self) -> bool {
270        self.annotation.is_some()
271    }
272
273    fn source(&self) -> Option<&SourceRef> {
274        self.source.as_ref()
275    }
276
277    fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
278        self.foreign_attributes = attrs;
279    }
280}
281