xsd_schema/parser/frames/
identity.rs1pub struct SelectorFrame {
7 xpath: String,
8 xpath_default_namespace: Option<String>,
9 ns_snapshot: NamespaceContextSnapshot,
10 id: Option<String>,
11 annotation: Option<Annotation>,
12 source: Option<SourceRef>,
13 foreign_attributes: Vec<ForeignAttribute>,
14}
15
16impl SelectorFrame {
17 pub fn new(
18 attrs: &AttributeMap,
19 name_table: &NameTable,
20 source: Option<SourceRef>,
21 ns_snapshot: NamespaceContextSnapshot,
22 ) -> SchemaResult<Self> {
23 let xpath = attrs
24 .get_value_by_name(name_table, "xpath")
25 .map(String::from)
26 .unwrap_or_default();
27
28 #[cfg(feature = "xsd11")]
29 let xpath_default_namespace = attrs
30 .get_value_by_name(name_table, "xpathDefaultNamespace")
31 .map(String::from);
32 #[cfg(not(feature = "xsd11"))]
33 let xpath_default_namespace: Option<String> = None;
34
35 let id = attrs
36 .get_value_by_name(name_table, "id")
37 .map(String::from);
38
39 Ok(Self {
40 xpath,
41 xpath_default_namespace,
42 ns_snapshot,
43 id,
44 annotation: None,
45 source,
46 foreign_attributes: Vec::new(),
47 })
48 }
49}
50
51impl Frame for SelectorFrame {
52 fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
53 matches!(local_name, xsd_names::ANNOTATION)
54 }
55
56 fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
57 #[cfg(feature = "xsd11")]
58 if local_name == "xpathDefaultNamespace" {
59 return true;
60 }
61 matches!(local_name, "xpath" | "id")
62 }
63
64 fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {}
65
66 fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
67 if let FrameResult::Annotation(ann) = child {
68 self.annotation = Some(ann);
69 }
70 Ok(())
71 }
72
73 fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
74 let annotation = merge_foreign_attributes(
75 self.annotation,
76 self.foreign_attributes,
77 self.source.clone(),
78 );
79 Ok(FrameResult::Selector(SelectorResult {
80 xpath: self.xpath,
81 xpath_default_namespace: self.xpath_default_namespace,
82 ns_snapshot: self.ns_snapshot,
83 id: self.id,
84 annotation,
85 source: self.source,
86 }))
87 }
88
89 fn has_annotation(&self) -> bool {
90 self.annotation.is_some()
91 }
92
93 fn source(&self) -> Option<&SourceRef> {
94 self.source.as_ref()
95 }
96
97 fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
98 self.foreign_attributes = attrs;
99 }
100}
101
102pub struct FieldFrame {
104 xpath: String,
105 xpath_default_namespace: Option<String>,
106 ns_snapshot: NamespaceContextSnapshot,
107 id: Option<String>,
108 annotation: Option<Annotation>,
109 source: Option<SourceRef>,
110 foreign_attributes: Vec<ForeignAttribute>,
111}
112
113impl FieldFrame {
114 pub fn new(
115 attrs: &AttributeMap,
116 name_table: &NameTable,
117 source: Option<SourceRef>,
118 ns_snapshot: NamespaceContextSnapshot,
119 ) -> SchemaResult<Self> {
120 let xpath = attrs
121 .get_value_by_name(name_table, "xpath")
122 .map(String::from)
123 .unwrap_or_default();
124
125 #[cfg(feature = "xsd11")]
126 let xpath_default_namespace = attrs
127 .get_value_by_name(name_table, "xpathDefaultNamespace")
128 .map(String::from);
129 #[cfg(not(feature = "xsd11"))]
130 let xpath_default_namespace: Option<String> = None;
131
132 let id = attrs
133 .get_value_by_name(name_table, "id")
134 .map(String::from);
135
136 Ok(Self {
137 xpath,
138 xpath_default_namespace,
139 ns_snapshot,
140 id,
141 annotation: None,
142 source,
143 foreign_attributes: Vec::new(),
144 })
145 }
146}
147
148impl Frame for FieldFrame {
149 fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
150 matches!(local_name, xsd_names::ANNOTATION)
151 }
152
153 fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
154 #[cfg(feature = "xsd11")]
155 if local_name == "xpathDefaultNamespace" {
156 return true;
157 }
158 matches!(local_name, "xpath" | "id")
159 }
160
161 fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {}
162
163 fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
164 if let FrameResult::Annotation(ann) = child {
165 self.annotation = Some(ann);
166 }
167 Ok(())
168 }
169
170 fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
171 let annotation = merge_foreign_attributes(
172 self.annotation,
173 self.foreign_attributes,
174 self.source.clone(),
175 );
176 Ok(FrameResult::Field(FieldResult {
177 xpath: self.xpath,
178 xpath_default_namespace: self.xpath_default_namespace,
179 ns_snapshot: self.ns_snapshot,
180 id: self.id,
181 annotation,
182 source: self.source,
183 }))
184 }
185
186 fn has_annotation(&self) -> bool {
187 self.annotation.is_some()
188 }
189
190 fn source(&self) -> Option<&SourceRef> {
191 self.source.as_ref()
192 }
193
194 fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
195 self.foreign_attributes = attrs;
196 }
197}
198
199pub struct IdentityFrame {
201 kind: IdentityKind,
202 name: Option<NameId>,
203 raw_name: Option<String>,
204 ref_name: Option<QNameRef>,
205 refer: Option<QNameRef>,
206 id: Option<String>,
207 selector: Option<SelectorResult>,
208 fields: Vec<FieldResult>,
209 annotation: Option<Annotation>,
210 source: Option<SourceRef>,
211 foreign_attributes: Vec<ForeignAttribute>,
212}
213
214impl IdentityFrame {
215 pub fn new(
216 kind: IdentityKind,
217 attrs: &AttributeMap,
218 name_table: &NameTable,
219 source: Option<SourceRef>,
220 ns_snapshot: &NamespaceContextSnapshot,
221 ) -> SchemaResult<Self> {
222 let raw_name = attrs
223 .get_value_by_name(name_table, "name")
224 .map(String::from);
225 let name = raw_name.as_deref()
226 .and_then(|s| name_table.get(s));
227
228 let ref_name = attrs
229 .get_value_by_name(name_table, "ref")
230 .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
231 .transpose()?;
232
233 let refer = if kind == IdentityKind::Keyref {
234 attrs
235 .get_value_by_name(name_table, "refer")
236 .map(|s| parse_qname_ref(s, name_table, ns_snapshot))
237 .transpose()?
238 } else {
239 None
240 };
241
242 let id = attrs
243 .get_value_by_name(name_table, "id")
244 .map(String::from);
245
246 Ok(Self {
247 kind,
248 name,
249 raw_name,
250 ref_name,
251 refer,
252 id,
253 selector: None,
254 fields: Vec::new(),
255 annotation: None,
256 source,
257 foreign_attributes: Vec::new(),
258 })
259 }
260}
261
262impl Frame for IdentityFrame {
263 fn allows(&self, local_name: &str, _name_table: &NameTable) -> bool {
264 if self.ref_name.is_some() {
266 return local_name == xsd_names::ANNOTATION
267 && !self.has_annotation();
268 }
269 if local_name == xsd_names::ANNOTATION {
271 return self.selector.is_none() && self.fields.is_empty() && !self.has_annotation();
273 }
274 if local_name == xsd_names::SELECTOR {
275 return self.selector.is_none() && self.fields.is_empty();
277 }
278 if local_name == xsd_names::FIELD {
279 return self.selector.is_some();
281 }
282 false
283 }
284
285 fn allows_attribute(&self, local_name: &str, _name_table: &NameTable) -> bool {
286 if local_name == "refer" {
287 return self.kind == IdentityKind::Keyref && self.ref_name.is_none();
290 }
291 matches!(local_name, "name" | "ref" | "id")
292 }
293
294 fn on_child_start(&mut self, _local_name: &str, _name_table: &NameTable) {}
295
296 fn attach(&mut self, child: FrameResult) -> SchemaResult<()> {
297 match child {
298 FrameResult::Annotation(ann) => {
299 self.annotation = Some(ann);
300 }
301 FrameResult::Selector(selector) => {
302 self.selector = Some(selector);
303 }
304 FrameResult::Field(field) => {
305 self.fields.push(field);
306 }
307 FrameResult::Skip => {}
308 _ => {}
309 }
310 Ok(())
311 }
312
313 fn finish(self: Box<Self>) -> SchemaResult<FrameResult> {
314 let annotation = merge_foreign_attributes(
315 self.annotation,
316 self.foreign_attributes,
317 self.source.clone(),
318 );
319
320 if let Some(ref_name) = self.ref_name {
322 if self.name.is_some() {
324 return Err(SchemaError::structural(
325 "src-identity-constraint.1",
326 "Identity constraint with 'ref' must not have 'name'",
327 None,
328 ));
329 }
330 return Ok(FrameResult::IdentityRef(IdentityRefResult {
331 kind: self.kind,
332 ref_name,
333 id: self.id,
334 annotation,
335 source: self.source,
336 }));
337 }
338
339 let name = match (&self.name, &self.raw_name) {
341 (Some(id), Some(raw)) if is_ncname(raw) => *id,
342 (_, Some(raw)) => {
343 return Err(SchemaError::structural(
344 "src-identity-constraint",
345 format!("Identity constraint 'name' attribute value '{}' is not a valid NCName", raw),
346 None,
347 ));
348 }
349 _ => {
350 return Err(SchemaError::structural(
351 "src-identity-constraint",
352 "Identity constraint requires 'name' attribute",
353 None,
354 ));
355 }
356 };
357
358 let selector = self.selector.ok_or_else(|| {
359 SchemaError::structural(
360 "src-identity-constraint",
361 "Identity constraint requires a selector",
362 None,
363 )
364 })?;
365
366 if self.fields.is_empty() {
367 return Err(SchemaError::structural(
368 "src-identity-constraint",
369 "Identity constraint requires at least one field",
370 None,
371 ));
372 }
373
374 Ok(FrameResult::Identity(IdentityResult {
375 kind: self.kind,
376 name,
377 ref_name: None,
378 refer: self.refer,
379 selector,
380 fields: self.fields,
381 id: self.id,
382 annotation,
383 source: self.source,
384 }))
385 }
386
387 fn has_annotation(&self) -> bool {
388 self.annotation.is_some()
389 }
390
391 fn source(&self) -> Option<&SourceRef> {
392 self.source.as_ref()
393 }
394
395 fn set_foreign_attributes(&mut self, attrs: Vec<ForeignAttribute>) {
396 self.foreign_attributes = attrs;
397 }
398}
399