1pub struct ModelGroupFrame {
7 compositor: Compositor,
8 min_occurs: u32,
9 max_occurs: Option<u32>,
10 id: Option<String>,
11 particles: Vec<ParticleResult>,
12 past_annotation: bool,
14 annotation: Option<Annotation>,
15 source: Option<SourceRef>,
16 foreign_attributes: Vec<ForeignAttribute>,
17}
18
19impl ModelGroupFrame {
20 pub fn new(
21 compositor: Compositor,
22 attrs: &AttributeMap,
23 name_table: &NameTable,
24 source: Option<SourceRef>,
25 _ns_snapshot: &NamespaceContextSnapshot,
26 ) -> SchemaResult<Self> {
27 let min_occurs = parse_min_occurs_attr(attrs, name_table, "minOccurs")?;
28
29 let max_occurs = parse_max_occurs_attr(attrs, name_table, "maxOccurs")?;
30
31 let id = attrs
32 .get_value_by_name(name_table, "id")
33 .map(String::from);
34
35 Ok(Self {
36 compositor,
37 min_occurs,
38 max_occurs,
39 id,
40 particles: Vec::new(),
41 past_annotation: false,
42 annotation: None,
43 source,
44 foreign_attributes: Vec::new(),
45 })
46 }
47}
48
49impl Frame for ModelGroupFrame {
50 fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
51 if local_name == xsd_names::ANNOTATION && self.past_annotation {
53 return false;
54 }
55 match self.compositor {
56 Compositor::All => matches!(
57 local_name,
58 xsd_names::ANNOTATION | xsd_names::ELEMENT | xsd_names::ANY | xsd_names::GROUP
59 ),
60 Compositor::Sequence | Compositor::Choice => matches!(
61 local_name,
62 xsd_names::ANNOTATION
63 | xsd_names::ELEMENT
64 | xsd_names::GROUP
65 | xsd_names::SEQUENCE
66 | xsd_names::CHOICE
67 | xsd_names::ANY
68 ),
69 }
70 }
71
72 fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
73 matches!(local_name, "minOccurs" | "maxOccurs" | "id")
74 }
75
76 fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
77 if local_name != xsd_names::ANNOTATION {
78 self.past_annotation = true;
79 }
80 }
81
82 fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
83 match child {
84 FrameResult::Annotation(ann) => {
85 self.annotation = Some(ann);
86 }
87 FrameResult::Element(elem) => {
88 let min_occurs = elem.min_occurs;
89 let max_occurs = elem.max_occurs;
90 let source = elem.source.clone();
91 self.particles.push(ParticleResult {
92 term: ParticleTerm::Element(elem),
93 min_occurs,
94 max_occurs,
95 source,
96 });
97 }
98 FrameResult::Particle(particle) => {
99 self.particles.push(particle);
100 }
101 FrameResult::Wildcard(wc) => {
102 let source = wc.source.clone();
103 self.particles.push(ParticleResult {
104 term: ParticleTerm::Any(wc),
105 min_occurs: 1,
106 max_occurs: Some(1),
107 source,
108 });
109 }
110 FrameResult::Group(GroupFrameResult::Model(mg)) => {
111 let min_occurs = mg.min_occurs;
112 let max_occurs = mg.max_occurs;
113 let source = mg.source.clone();
114 self.particles.push(ParticleResult {
115 term: ParticleTerm::Group(*mg),
116 min_occurs,
117 max_occurs,
118 source,
119 });
120 }
121 FrameResult::Skip => {}
122 _ => {}
123 }
124 Ok(())
125 }
126
127 fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
128 let annotation = merge_foreign_attributes(
129 self.annotation,
130 self.foreign_attributes,
131 self.source.clone(),
132 );
133 Ok(FrameResult::Particle(ParticleResult {
134 term: ParticleTerm::Group(ModelGroupDefResult {
135 name: None,
136 ref_name: None,
137 compositor: Some(self.compositor),
138 particles: self.particles,
139 min_occurs: self.min_occurs,
140 max_occurs: self.max_occurs,
141 id: self.id,
142 annotation,
143 source: self.source.clone(),
144 }),
145 min_occurs: self.min_occurs,
146 max_occurs: self.max_occurs,
147 source: self.source,
148 }))
149 }
150
151 fn has_annotation(&self) -> bool {
152 self.annotation.is_some()
153 }
154
155 fn source(&self) -> Option<&SourceRef> {
156 self.source.as_ref()
157 }
158
159 fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
160 self.foreign_attributes = attrs;
161 }
162}
163
164pub struct GroupFrame {
170 name: Option<NameId>,
171 ref_name: Option<QNameRef>,
172 min_occurs: u32,
173 max_occurs: Option<u32>,
174 id: Option<String>,
175 compositor: Option<Compositor>,
176 particles: Vec<ParticleResult>,
177 past_annotation: bool,
179 annotation: Option<Annotation>,
180 source: Option<SourceRef>,
181 foreign_attributes: Vec<ForeignAttribute>,
182}
183
184impl GroupFrame {
185 pub fn new(
186 attrs: &AttributeMap,
187 name_table: &NameTable,
188 source: Option<SourceRef>,
189 ns_snapshot: &NamespaceContextSnapshot,
190 ) -> SchemaResult<Self> {
191 let name = attrs
192 .get_value_by_name(name_table, "name")
193 .and_then(|s| name_table.get(s));
194
195 let ref_name = attrs
196 .get_value_by_name(name_table, "ref")
197 .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
198 .transpose()?;
199
200 let min_occurs = parse_min_occurs_attr(attrs, name_table, "minOccurs")?;
201
202 let max_occurs = parse_max_occurs_attr(attrs, name_table, "maxOccurs")?;
203
204 let id = attrs
205 .get_value_by_name(name_table, "id")
206 .map(String::from);
207
208 Ok(Self {
209 name,
210 ref_name,
211 min_occurs,
212 max_occurs,
213 id,
214 compositor: None,
215 particles: Vec::new(),
216 past_annotation: false,
217 annotation: None,
218 source,
219 foreign_attributes: Vec::new(),
220 })
221 }
222}
223
224impl Frame for GroupFrame {
225 fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
226 if local_name == xsd_names::ANNOTATION && self.past_annotation {
228 return false;
229 }
230 if self.ref_name.is_some() {
233 return local_name == xsd_names::ANNOTATION;
234 }
235 if self.compositor.is_some()
237 && matches!(
238 local_name,
239 xsd_names::SEQUENCE | xsd_names::CHOICE | xsd_names::ALL
240 )
241 {
242 return false;
243 }
244 matches!(
245 local_name,
246 xsd_names::ANNOTATION | xsd_names::SEQUENCE | xsd_names::CHOICE | xsd_names::ALL
247 )
248 }
249
250 fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
251 matches!(
252 local_name,
253 "name" | "ref" | "minOccurs" | "maxOccurs" | "id"
254 )
255 }
256
257 fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
258 if local_name != xsd_names::ANNOTATION {
259 self.past_annotation = true;
260 }
261 }
262
263 fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
264 match child {
265 FrameResult::Annotation(ann) => {
266 self.annotation = Some(ann);
267 }
268 FrameResult::Particle(ParticleResult {
269 term: ParticleTerm::Group(mg),
270 min_occurs,
271 max_occurs,
272 ..
273 }) => {
274 if self.compositor.is_some() {
278 return Err(SchemaError::structural(
279 "src-group",
280 "Group definition must have exactly one compositor child (sequence, choice, or all)",
281 None,
282 ));
283 }
284 if self.name.is_some() && (min_occurs != 1 || max_occurs != Some(1)) {
287 return Err(SchemaError::structural(
288 "src-group",
289 "Compositor in top-level group definition cannot have minOccurs/maxOccurs",
290 None,
291 ));
292 }
293 self.compositor = mg.compositor;
294 self.particles = mg.particles;
295 }
296 FrameResult::Skip => {}
297 _ => {}
298 }
299 Ok(())
300 }
301
302 fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
303 if self.name.is_some() && self.ref_name.is_none() && self.compositor.is_none() {
305 return Err(SchemaError::structural(
306 "src-group",
307 "Named group definition must contain a compositor (sequence, choice, or all)",
308 None,
309 ));
310 }
311 let annotation = merge_foreign_attributes(
312 self.annotation,
313 self.foreign_attributes,
314 self.source.clone(),
315 );
316 Ok(FrameResult::Group(GroupFrameResult::Model(Box::new(ModelGroupDefResult {
317 name: self.name,
318 ref_name: self.ref_name,
319 compositor: self.compositor,
320 particles: self.particles,
321 min_occurs: self.min_occurs,
322 max_occurs: self.max_occurs,
323 id: self.id,
324 annotation,
325 source: self.source,
326 }))))
327 }
328
329 fn has_annotation(&self) -> bool {
330 self.annotation.is_some()
331 }
332
333 fn source(&self) -> Option<&SourceRef> {
334 self.source.as_ref()
335 }
336
337 fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
338 self.foreign_attributes = attrs;
339 }
340}
341
342pub struct AttributeGroupFrame {
348 name: Option<NameId>,
349 ref_name: Option<QNameRef>,
350 id: Option<String>,
351 attributes: Vec<AttributeUseResult>,
352 attribute_groups: Vec<QNameRef>,
353 attribute_wildcard: Option<WildcardResult>,
354 past_annotation: bool,
356 annotation: Option<Annotation>,
357 source: Option<SourceRef>,
358 foreign_attributes: Vec<ForeignAttribute>,
359}
360
361impl AttributeGroupFrame {
362 pub fn new(
363 attrs: &AttributeMap,
364 name_table: &NameTable,
365 source: Option<SourceRef>,
366 ns_snapshot: &NamespaceContextSnapshot,
367 ) -> SchemaResult<Self> {
368 let name = attrs
369 .get_value_by_name(name_table, "name")
370 .and_then(|s| name_table.get(s));
371
372 let ref_name = attrs
373 .get_value_by_name(name_table, "ref")
374 .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
375 .transpose()?;
376
377 let id = attrs
378 .get_value_by_name(name_table, "id")
379 .map(String::from);
380
381 Ok(Self {
382 name,
383 ref_name,
384 id,
385 attributes: Vec::new(),
386 attribute_groups: Vec::new(),
387 attribute_wildcard: None,
388 past_annotation: false,
389 annotation: None,
390 source,
391 foreign_attributes: Vec::new(),
392 })
393 }
394}
395
396impl Frame for AttributeGroupFrame {
397 fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
398 if local_name == xsd_names::ANNOTATION && self.past_annotation {
400 return false;
401 }
402 if self.ref_name.is_some() {
405 return local_name == xsd_names::ANNOTATION;
406 }
407 matches!(
408 local_name,
409 xsd_names::ANNOTATION
410 | xsd_names::ATTRIBUTE
411 | xsd_names::ATTRIBUTE_GROUP
412 | xsd_names::ANY_ATTRIBUTE
413 )
414 }
415
416 fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
417 matches!(local_name, "name" | "ref" | "id")
418 }
419
420 fn on_child_start(&mut self, local_name: &str, _name_table: &NameTable) {
421 if local_name != xsd_names::ANNOTATION {
422 self.past_annotation = true;
423 }
424 }
425
426 fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
427 match child {
428 FrameResult::Annotation(ann) => {
429 self.annotation = Some(ann);
430 }
431 FrameResult::Attribute(attr) => {
432 let use_kind = match attr.use_kind.as_deref() {
433 Some("required") => AttributeUseKind::Required,
434 Some("prohibited") => AttributeUseKind::Prohibited,
435 _ => AttributeUseKind::Optional,
436 };
437 self.attributes.push(AttributeUseResult {
438 attribute: attr,
439 use_kind,
440 });
441 }
442 FrameResult::Group(GroupFrameResult::Attribute(ag)) => {
443 if let Some(ref_name) = ag.ref_name {
444 self.attribute_groups.push(ref_name);
445 }
446 }
447 FrameResult::Wildcard(wc) => {
448 self.attribute_wildcard = Some(wc);
449 }
450 FrameResult::Skip => {}
451 _ => {}
452 }
453 Ok(())
454 }
455
456 fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
457 let annotation = merge_foreign_attributes(
458 self.annotation,
459 self.foreign_attributes,
460 self.source.clone(),
461 );
462 Ok(FrameResult::Group(GroupFrameResult::Attribute(Box::new(AttributeGroupDefResult {
463 name: self.name,
464 ref_name: self.ref_name,
465 attributes: self.attributes,
466 attribute_groups: self.attribute_groups,
467 attribute_wildcard: self.attribute_wildcard,
468 id: self.id,
469 annotation,
470 source: self.source,
471 }))))
472 }
473
474 fn has_annotation(&self) -> bool {
475 self.annotation.is_some()
476 }
477
478 fn source(&self) -> Option<&SourceRef> {
479 self.source.as_ref()
480 }
481
482 fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
483 self.foreign_attributes = attrs;
484 }
485}
486