Package xmlschema_acue ::
Package validators ::
Module attributes
1
2
3
4
5
6
7
8
9
10
11 """
12 This module contains classes for XML Schema attributes and attribute groups.
13 """
14 from __future__ import unicode_literals
15 from decimal import Decimal
16 from elementpath.datatypes import AbstractDateTime, Duration
17
18 from xmlschema_acue.compat import MutableMapping, ordered_dict_class
19 from xmlschema_acue.exceptions import XMLSchemaAttributeError, XMLSchemaTypeError, XMLSchemaValueError
20 from xmlschema_acue.qnames import XSD_ANY_SIMPLE_TYPE, XSD_SIMPLE_TYPE, XSD_ATTRIBUTE_GROUP, XSD_COMPLEX_TYPE, \
21 XSD_RESTRICTION, XSD_EXTENSION, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE
22 from xmlschema_acue.helpers import get_namespace, get_qname, get_xsd_form_attribute
23 from xmlschema_acue.namespaces import XSI_NAMESPACE
24
25 from xmlschema_acue.validators.exceptions import XMLSchemaValidationError
26 from xmlschema_acue.validators.xsdbase import XsdComponent, ValidationMixin
27 from xmlschema_acue.validators.simple_types import XsdSimpleType
28 from xmlschema_acue.validators.wildcards import XsdAnyAttribute
32 """
33 Class for XSD 1.0 'attribute' declarations.
34
35 <attribute
36 default = string
37 fixed = string
38 form = (qualified | unqualified)
39 id = ID
40 name = NCName
41 ref = QName
42 type = QName
43 use = (optional | prohibited | required) : optional
44 {any attributes with non-schema namespace ...}>
45 Content: (annotation?, simpleType?)
46 </attribute>
47 """
48 _admitted_tags = {XSD_ATTRIBUTE}
49 qualified = False
50
51 - def __init__(self, elem, schema, parent, name=None, xsd_type=None):
58
60 if self.ref is None:
61 return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name)
62 else:
63 return '%s(ref=%r)' % (self.__class__.__name__, self.prefixed_name)
64
70
72 super(XsdAttribute, self)._parse()
73 elem = self.elem
74
75 try:
76 form = self.form
77 except ValueError as err:
78 self.parse_error(err)
79 else:
80 if form is None:
81 self.qualified = self.schema.attribute_form_default == 'qualified'
82 elif self.parent is None:
83 self.parse_error("attribute 'form' not allowed in a global attribute.")
84 else:
85 self.qualified = form == 'qualified'
86
87 self.use = elem.get('use')
88 if self.use is None:
89 self.use = 'optional'
90 elif self.parent is None:
91 self.parse_error("attribute 'use' not allowed in a global attribute.")
92 elif self.use not in {'optional', 'prohibited', 'required'}:
93 self.parse_error("wrong value %r for 'use' attribute." % self.use)
94 self.use = 'optional'
95
96 name = elem.get('name')
97 if name is not None:
98 if 'ref' in elem.attrib:
99 self.parse_error("both 'name' and 'ref' in attribute declaration")
100 elif name == 'xmlns':
101 self.parse_error("an attribute name must be different from 'xmlns'")
102
103 if self.parent is None or self.qualified:
104 if self.target_namespace == XSI_NAMESPACE and \
105 name not in {'nil', 'type', 'schemaLocation', 'noNamespaceSchemaLocation'}:
106 self.parse_error("Cannot add attributes in %r namespace" % XSI_NAMESPACE)
107 self.name = get_qname(self.target_namespace, name)
108 else:
109 self.name = name
110 elif self.parent is None:
111 self.parse_error("missing 'name' in global attribute declaration")
112 else:
113 try:
114 attribute_qname = self.schema.resolve_qname(elem.attrib['ref'])
115 except KeyError:
116 self.parse_error("missing both 'name' and 'ref' in attribute declaration")
117 self.xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
118 return
119 except ValueError as err:
120 self.parse_error(err)
121 self.xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
122 return
123 else:
124 try:
125 xsd_attribute = self.maps.lookup_attribute(attribute_qname)
126 except LookupError:
127 self.parse_error("unknown attribute %r" % elem.attrib['ref'])
128 self.type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
129 else:
130 self.type = xsd_attribute.type
131 self.qualified = xsd_attribute.qualified
132 if xsd_attribute.fixed is not None and 'fixed' in elem.attrib and \
133 elem.get('fixed') != xsd_attribute.fixed:
134 self.parse_error("referenced attribute has a different fixed value %r" % xsd_attribute.fixed)
135
136 self.name = attribute_qname
137 for attribute in ('form', 'type'):
138 if attribute in self.elem.attrib:
139 self.parse_error("attribute %r is not allowed when attribute reference is used." % attribute)
140 xsd_declaration = self._parse_component(elem, required=False)
141
142 if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE:
143 self.parse_error("not allowed type declaration for XSD attribute reference")
144 return
145
146 xsd_declaration = self._parse_component(elem, required=False)
147 try:
148 type_qname = self.schema.resolve_qname(elem.attrib['type'])
149 except ValueError as err:
150 self.parse_error(err, elem)
151 xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
152 except KeyError:
153 if xsd_declaration is not None:
154
155 xsd_type = self.schema.BUILDERS.simple_type_factory(xsd_declaration, self.schema, self)
156 else:
157
158 xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
159 else:
160 try:
161 xsd_type = self.maps.lookup_type(type_qname)
162 except LookupError as err:
163 self.parse_error(err, elem)
164 xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
165
166 if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE:
167 self.parse_error("ambiguous type declaration for XSD attribute")
168 elif xsd_declaration:
169 self.parse_error("not allowed element in XSD attribute declaration: %r" % xsd_declaration[0])
170
171 try:
172 self.type = xsd_type
173 except TypeError as err:
174 self.parse_error(err)
175
176
177 if 'default' in elem.attrib:
178 if 'fixed' in elem.attrib:
179 self.parse_error("'default' and 'fixed' attributes are mutually exclusive")
180 if self.use != 'optional':
181 self.parse_error("the attribute 'use' must be 'optional' if the attribute 'default' is present")
182 if not self.type.is_valid(elem.attrib['default']):
183 msg = "'default' value {!r} is not compatible with the type {!r}"
184 self.parse_error(msg.format(elem.attrib['default'], self.type))
185 elif self.type.is_key():
186 self.parse_error("'xs:ID' or a type derived from 'xs:ID' cannot has a 'default'")
187 elif 'fixed' in elem.attrib:
188 if not self.type.is_valid(elem.attrib['fixed']):
189 msg = "'fixed' value {!r} is not compatible with the type {!r}"
190 self.parse_error(msg.format(elem.attrib['fixed'], self.type))
191 elif self.type.is_key():
192 self.parse_error("'xs:ID' or a type derived from 'xs:ID' cannot has a 'default'")
193
194 @property
197
198 @property
204
205
206 @property
208 return self.elem.get('ref')
209
210 @property
212 return self.elem.get('default')
213
214 @property
216 return self.elem.get('fixed')
217
218 @property
221
223 return self.use == 'optional'
224
226 if xsd_classes is None or isinstance(self, xsd_classes):
227 yield self
228 if self.ref is None and self.type.parent is not None:
229 for obj in self.type.iter_components(xsd_classes):
230 yield obj
231
232 - def iter_decode(self, text, validation='lax', **kwargs):
233 if not text and kwargs.get('use_defaults', True) and self.default is not None:
234 text = self.default
235 if self.fixed is not None and text != self.fixed and validation != 'skip':
236 yield self.validation_error(validation, "value differs from fixed value", text, **kwargs)
237
238 for result in self.type.iter_decode(text, validation, **kwargs):
239 if isinstance(result, XMLSchemaValidationError):
240 yield result
241 elif isinstance(result, Decimal):
242 try:
243 yield kwargs['decimal_type'](result)
244 except (KeyError, TypeError):
245 yield result
246 break
247 elif isinstance(result, (AbstractDateTime, Duration)):
248 try:
249 yield result if kwargs['datetime_types'] is True else text
250 except KeyError:
251 yield text
252 else:
253 yield result
254 break
255
256 - def iter_encode(self, obj, validation='lax', **kwargs):
261
264 """
265 Class for XSD 1.1 'attribute' declarations.
266
267 <attribute
268 default = string
269 fixed = string
270 form = (qualified | unqualified)
271 id = ID
272 name = NCName
273 ref = QName
274 targetNamespace = anyURI
275 type = QName
276 use = (optional | prohibited | required) : optional
277 inheritable = boolean
278 {any attributes with non-schema namespace . . .}>
279 Content: (annotation?, simpleType?)
280 </attribute>
281 """
282 @property
284 return self.elem.get('inheritable') in ('0', 'true')
285
286 @property
289
291 super(Xsd11Attribute, self)._parse()
292 if not self.elem.get('inheritable') not in {'0', '1', 'false', 'true'}:
293 self.parse_error("an XML boolean value is required for attribute 'inheritable'")
294 self._parse_target_namespace()
295
298 """
299 Class for XSD 'attributeGroup' definitions.
300
301 <attributeGroup
302 id = ID
303 name = NCName
304 ref = QName
305 {any attributes with non-schema namespace . . .}>
306 Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?))
307 </attributeGroup>
308 """
309 redefine = None
310 _admitted_tags = {
311 XSD_ATTRIBUTE_GROUP, XSD_COMPLEX_TYPE, XSD_RESTRICTION, XSD_EXTENSION,
312 XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE
313 }
314
315 - def __init__(self, elem, schema, parent, name=None, derivation=None, base_attributes=None):
320
322 if self.ref is not None:
323 return '%s(ref=%r)' % (self.__class__.__name__, self.prefixed_name)
324 elif self.name is not None:
325 return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name)
326 elif self:
327 names = [a if a.name is None else a.prefixed_name for a in self.values()]
328 return '%s(%r)' % (self.__class__.__name__, names)
329 else:
330 return '%s()' % self.__class__.__name__
331
332
334 return self._attribute_group[key]
335
352
354 del self._attribute_group[key]
355
357 if None in self._attribute_group:
358
359 return iter(sorted(self._attribute_group, key=lambda x: (x is None, x)))
360 else:
361 return iter(self._attribute_group)
362
364 return len(self._attribute_group)
365
366
368 super(XsdAttributeGroup, self).__setattr__(name, value)
369 if name == '_attribute_group':
370 assert isinstance(value, dict), 'A dictionary object is required.'
371 for k, v in value.items():
372 if k is None:
373 assert isinstance(value, XsdAnyAttribute), 'An XsdAnyAttribute instance is required.'
374 else:
375 assert isinstance(value, XsdAttribute), 'An XsdAttribute instance is required.'
376
378 super(XsdAttributeGroup, self)._parse()
379 elem = self.elem
380 any_attribute = False
381 attribute_group_refs = []
382
383 if elem.tag == XSD_ATTRIBUTE_GROUP:
384 if self.parent is not None:
385 return
386 try:
387 self.name = get_qname(self.target_namespace, self.elem.attrib['name'])
388 except KeyError:
389 self.parse_error("an attribute group declaration requires a 'name' attribute.")
390 return
391
392 attributes = ordered_dict_class()
393 for child in self._iterparse_components(elem):
394 if any_attribute:
395 if child.tag == XSD_ANY_ATTRIBUTE:
396 self.parse_error("more anyAttribute declarations in the same attribute group")
397 else:
398 self.parse_error("another declaration after anyAttribute")
399
400 elif child.tag == XSD_ANY_ATTRIBUTE:
401 any_attribute = True
402 attributes.update([(None, XsdAnyAttribute(child, self.schema, self))])
403
404 elif child.tag == XSD_ATTRIBUTE:
405 attribute = self.schema.BUILDERS.attribute_class(child, self.schema, self)
406 if attribute.name in attributes:
407 self.parse_error("multiple declaration for attribute {!r}".format(attribute.name))
408 else:
409 attributes[attribute.name] = attribute
410
411 elif child.tag == XSD_ATTRIBUTE_GROUP:
412 try:
413 ref = child.attrib['ref']
414 attribute_group_qname = self.schema.resolve_qname(ref)
415 except ValueError as err:
416 self.parse_error(err, elem)
417 except KeyError:
418 self.parse_error("the attribute 'ref' is required in a local attributeGroup", elem)
419 else:
420 if attribute_group_qname in attribute_group_refs:
421 self.parse_error("duplicated attributeGroup %r" % ref)
422 elif self.redefine is not None:
423 if attribute_group_qname == self.name:
424 if attribute_group_refs:
425 self.parse_error("in a redefinition the reference to itself must be the first")
426 attribute_group_refs.append(attribute_group_qname)
427 attributes.update(self._attribute_group.items())
428 continue
429 elif not attribute_group_refs:
430
431 if not any(e.tag == XSD_ATTRIBUTE_GROUP and ref == e.get('ref')
432 for e in self.redefine.elem):
433 self.parse_error("attributeGroup ref=%r is not in the redefined group" % ref)
434 elif attribute_group_qname == self.name and self.schema.XSD_VERSION == '1.0':
435 self.parse_error("Circular attribute groups not allowed in XSD 1.0")
436 attribute_group_refs.append(attribute_group_qname)
437
438 try:
439 base_attributes = self.maps.lookup_attribute_group(attribute_group_qname)
440 except LookupError:
441 self.parse_error("unknown attribute group %r" % child.attrib['ref'], elem)
442 else:
443 if isinstance(base_attributes, tuple):
444 self.parse_error("Circular reference found between attribute groups "
445 "{!r} and {!r}".format(self.name, attribute_group_qname))
446
447 for name, attr in base_attributes.items():
448 if name is not None and name in attributes:
449 self.parse_error("multiple declaration for attribute {!r}".format(name))
450 else:
451 attributes[name] = attr
452
453 elif self.name is not None:
454 self.parse_error("(attribute | attributeGroup) expected, found %r." % child)
455
456
457 if self.base_attributes is not None:
458 wildcard = self.base_attributes.get(None)
459 for name, attr in attributes.items():
460 if name not in self.base_attributes:
461 if self.derivation != 'restriction':
462 continue
463 elif wildcard is None or not wildcard.is_matching(name, self.default_namespace):
464 self.parse_error("Unexpected attribute %r in restriction" % name)
465 continue
466
467 base_attr = self.base_attributes[name]
468
469 if name is None:
470 if self.derivation == 'extension':
471 try:
472 attr.extend_namespace(base_attr)
473 except ValueError as err:
474 self.parse_error(err)
475 elif not attr.is_restriction(base_attr):
476 self.parse_error("Attribute wildcard is not a restriction of the base wildcard")
477 continue
478 if self.derivation == 'restriction' and attr.type.name != XSD_ANY_SIMPLE_TYPE and \
479 not attr.type.is_derived(base_attr.type, 'restriction'):
480 self.parse_error("Attribute type is not a restriction of the base attribute type")
481 if base_attr.use != 'optional' and attr.use == 'optional' or \
482 base_attr.use == 'required' and attr.use != 'required':
483 self.parse_error("Attribute %r: unmatched attribute use in restriction" % name)
484 if base_attr.fixed is not None and \
485 attr.type.normalize(attr.fixed) != base_attr.type.normalize(base_attr.fixed):
486 self.parse_error("Attribute %r: derived attribute has a different fixed value" % name)
487
488 self._attribute_group.update(self.base_attributes.items())
489 elif self.redefine is not None and not attribute_group_refs:
490 for name, attr in self._attribute_group.items():
491 if name is None:
492 continue
493 elif name not in attributes:
494 if attr.use == 'required':
495 self.parse_error("Missing required attribute %r in redefinition restriction" % name)
496 continue
497 if attr.use != 'optional' and attributes[name].use != attr.use:
498 self.parse_error("Attribute %r: unmatched attribute use in redefinition" % name)
499 if attr.fixed is not None and attributes[name].fixed is None:
500 self.parse_error("Attribute %r: redefinition remove fixed constraint" % name)
501
502 pos = 0
503 keys = list(self._attribute_group.keys())
504 for name in attributes:
505 try:
506 next_pos = keys.index(name)
507 except ValueError:
508 self.parse_error("Redefinition restriction contains additional attribute %r" % name)
509 else:
510 if next_pos < pos:
511 self.parse_error("Wrong attribute order in redefinition restriction")
512 break
513 pos = next_pos
514 self.clear()
515
516 self._attribute_group.update(attributes)
517
518 if self.schema.XSD_VERSION == '1.0':
519 has_key = False
520 for attr in self._attribute_group.values():
521 if attr.name is not None and attr.type.is_key():
522 if has_key:
523 self.parse_error("multiple key attributes in a group not allowed in XSD 1.0")
524 has_key = True
525
526 elif self.parent is None and self.schema.default_attributes == self.name:
527 self.schema.default_attributes = self
528
529 @property
531 return all([attr.built for attr in self.values()])
532
533 @property
535 if self.built:
536 return 'full'
537 elif any([attr.validation_attempted == 'partial' for attr in self.values()]):
538 return 'partial'
539 else:
540 return 'none'
541
542 @property
544 return self.elem.get('ref')
545
547 for k, v in self._attribute_group.items():
548 if k is not None and v.use == 'required':
549 yield k
550
552 if xsd_classes is None or isinstance(self, xsd_classes):
553 yield self
554 if self.ref is None:
555 for attr in self.values():
556 if attr.parent is not None:
557 for obj in attr.iter_components(xsd_classes):
558 yield obj
559
560 - def iter_decode(self, attrs, validation='lax', **kwargs):
561 if not attrs and not self:
562 return
563
564 result_list = []
565 required_attributes = {a for a in self.iter_required()}
566 for name, value in attrs.items():
567 try:
568 xsd_attribute = self[name]
569 except KeyError:
570 if get_namespace(name) == XSI_NAMESPACE:
571 try:
572 xsd_attribute = self.maps.lookup_attribute(name)
573 except LookupError:
574 if validation != 'skip':
575 reason = "%r is not an attribute of the XSI namespace." % name
576 yield self.validation_error(validation, reason, attrs, **kwargs)
577 continue
578 else:
579 try:
580 xsd_attribute = self[None]
581 value = (name, value)
582 except KeyError:
583 if validation != 'skip':
584 reason = "%r attribute not allowed for element." % name
585 yield self.validation_error(validation, reason, attrs, **kwargs)
586 continue
587 else:
588 required_attributes.discard(name)
589
590 for result in xsd_attribute.iter_decode(value, validation, **kwargs):
591 if isinstance(result, XMLSchemaValidationError):
592 yield result
593 else:
594 result_list.append((name, result))
595 break
596
597 if required_attributes and validation != 'skip':
598 reason = "missing required attributes: %r" % required_attributes
599 yield self.validation_error(validation, reason, attrs, **kwargs)
600
601 yield result_list
602
603 - def iter_encode(self, attrs, validation='lax', **kwargs):
604 result_list = []
605 required_attributes = {a for a in self.iter_required()}
606 try:
607 attrs = attrs.items()
608 except AttributeError:
609 pass
610
611 for name, value in attrs:
612 try:
613 xsd_attribute = self[name]
614 except KeyError:
615 namespace = get_namespace(name) or self.target_namespace
616 if namespace == XSI_NAMESPACE:
617 try:
618 xsd_attribute = self.maps.lookup_attribute(name)
619 except LookupError:
620 if validation != 'skip':
621 reason = "%r is not an attribute of the XSI namespace." % name
622 yield self.validation_error(validation, reason, attrs, **kwargs)
623 continue
624 else:
625 try:
626 xsd_attribute = self[None]
627 value = (name, value)
628 except KeyError:
629 if validation != 'skip':
630 reason = "%r attribute not allowed for element." % name
631 yield self.validation_error(validation, reason, attrs, **kwargs)
632 continue
633 else:
634 required_attributes.discard(name)
635
636 for result in xsd_attribute.iter_encode(value, validation, **kwargs):
637 if isinstance(result, XMLSchemaValidationError):
638 yield result
639 else:
640 result_list.append((name, result))
641 break
642
643 if required_attributes and validation != 'skip':
644 reason = "missing required attributes %r" % required_attributes
645 yield self.validation_error(validation, reason, attrs, **kwargs)
646 yield result_list
647