Package xmlschema_acue :: Package validators :: Module groups

Source Code for Module xmlschema_acue.validators.groups

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # Copyright (c), 2016-2019, SISSA (International School for Advanced Studies). 
  4  # All rights reserved. 
  5  # This file is distributed under the terms of the MIT License. 
  6  # See the file 'LICENSE' in the root directory of the present 
  7  # distribution, or http://opensource.org/licenses/MIT. 
  8  # 
  9  # @author Davide Brunato <brunato@sissa.it> 
 10  # 
 11  """ 
 12  This module contains classes for XML Schema model groups. 
 13  """ 
 14  from __future__ import unicode_literals 
 15   
 16  from xmlschema_acue.compat import unicode_type 
 17  from xmlschema_acue.exceptions import XMLSchemaValueError 
 18  from xmlschema_acue.etree import etree_element 
 19  from xmlschema_acue.qnames import XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_COMPLEX_TYPE, \ 
 20      XSD_ELEMENT, XSD_ANY, XSD_RESTRICTION, XSD_EXTENSION 
 21  from xmlschema_acue.helpers import get_qname, local_name 
 22  from xmlschema_acue.converters import XMLSchemaConverter 
 23   
 24  from xmlschema_acue.validators.exceptions import XMLSchemaValidationError, XMLSchemaChildrenValidationError 
 25  from xmlschema_acue.validators.xsdbase import ValidationMixin, XsdComponent, XsdType 
 26  from xmlschema_acue.validators.elements import XsdElement 
 27  from xmlschema_acue.validators.wildcards import XsdAnyElement 
 28  from xmlschema_acue.validators.models import MAX_MODEL_DEPTH, ParticleMixin, ModelGroup, ModelVisitor 
 29   
 30  ANY_ELEMENT = etree_element( 
 31      XSD_ANY, 
 32      attrib={ 
 33          'namespace': '##any', 
 34          'processContents': 'lax', 
 35          'minOccurs': '0', 
 36          'maxOccurs': 'unbounded' 
 37      }) 
38 39 40 -class XsdGroup(XsdComponent, ModelGroup, ValidationMixin):
41 """ 42 A class for XSD 1.0 model group definitions. 43 44 <group 45 id = ID 46 maxOccurs = (nonNegativeInteger | unbounded) : 1 47 minOccurs = nonNegativeInteger : 1 48 name = NCName 49 ref = QName 50 {any attributes with non-schema namespace . . .}> 51 Content: (annotation?, (all | choice | sequence)?) 52 </group> 53 54 <all 55 id = ID 56 maxOccurs = 1 : 1 57 minOccurs = (0 | 1) : 1 58 {any attributes with non-schema namespace . . .}> 59 Content: (annotation?, element*) 60 </all> 61 62 <choice 63 id = ID 64 maxOccurs = (nonNegativeInteger | unbounded) : 1 65 minOccurs = nonNegativeInteger : 1 66 {any attributes with non-schema namespace . . .}> 67 Content: (annotation?, (element | group | choice | sequence | any)*) 68 </choice> 69 70 <sequence 71 id = ID 72 maxOccurs = (nonNegativeInteger | unbounded) : 1 73 minOccurs = nonNegativeInteger : 1 74 {any attributes with non-schema namespace . . .}> 75 Content: (annotation?, (element | group | choice | sequence | any)*) 76 </sequence> 77 """ 78 mixed = False 79 model = None 80 redefine = None 81 _admitted_tags = { 82 XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_RESTRICTION, XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE 83 } 84
85 - def __init__(self, elem, schema, parent, name=None):
86 self._group = [] 87 if parent is not None and parent.mixed: 88 self.mixed = parent.mixed 89 super(XsdGroup, self).__init__(elem, schema, parent, name)
90
91 - def __repr__(self):
92 if self.name is None: 93 return '%s(model=%r, occurs=%r)' % (self.__class__.__name__, self.model, self.occurs) 94 elif self.ref is None: 95 return '%s(name=%r, model=%r, occurs=%r)' % ( 96 self.__class__.__name__, self.prefixed_name, self.model, self.occurs 97 ) 98 else: 99 return '%s(ref=%r, model=%r, occurs=%r)' % ( 100 self.__class__.__name__, self.prefixed_name, self.model, self.occurs 101 )
102
103 - def copy(self):
104 group = object.__new__(self.__class__) 105 group.__dict__.update(self.__dict__) 106 group.errors = self.errors[:] 107 group._group = self._group[:] 108 return group
109 110 __copy__ = copy 111
112 - def _parse(self):
113 super(XsdGroup, self)._parse() 114 self.clear() 115 elem = self.elem 116 self._parse_particle(elem) 117 118 if elem.tag == XSD_GROUP: 119 # Global group (group) 120 name = elem.get('name') 121 ref = elem.get('ref') 122 if name is None: 123 if ref is not None: 124 # Reference to a global group 125 if self.parent is None: 126 self.parse_error("a group reference cannot be global") 127 128 try: 129 self.name = self.schema.resolve_qname(ref) 130 except ValueError as err: 131 self.parse_error(err, elem) 132 return 133 134 try: 135 xsd_group = self.schema.maps.lookup_group(self.name) 136 except KeyError: 137 self.parse_error("missing group %r" % self.prefixed_name) 138 xsd_group = self.schema.create_any_content_group(self, self.name) 139 140 if isinstance(xsd_group, tuple): 141 # Disallowed circular definition, substitute with any content group. 142 self.parse_error("Circular definitions detected for group %r:" % self.ref, xsd_group[0]) 143 self.model = 'sequence' 144 self.mixed = True 145 self.append(XsdAnyElement(ANY_ELEMENT, self.schema, self)) 146 else: 147 self.model = xsd_group.model 148 if self.model == 'all': 149 if self.max_occurs != 1: 150 self.parse_error("maxOccurs must be 1 for 'all' model groups") 151 if self.min_occurs not in (0, 1): 152 self.parse_error("minOccurs must be (0 | 1) for 'all' model groups") 153 if self.schema.XSD_VERSION == '1.0' and isinstance(self.parent, XsdGroup): 154 self.parse_error("in XSD 1.0 the 'all' model group cannot be nested") 155 self.append(xsd_group) 156 else: 157 self.parse_error("missing both attributes 'name' and 'ref'") 158 return 159 elif ref is None: 160 # Global group 161 self.name = get_qname(self.target_namespace, name) 162 content_model = self._parse_component(elem) 163 if self.parent is not None: 164 self.parse_error("attribute 'name' not allowed for a local group") 165 else: 166 if 'minOccurs' in elem.attrib: 167 self.parse_error("attribute 'minOccurs' not allowed for a global group") 168 if 'maxOccurs' in elem.attrib: 169 self.parse_error("attribute 'maxOccurs' not allowed for a global group") 170 if 'minOccurs' in content_model.attrib: 171 self.parse_error( 172 "attribute 'minOccurs' not allowed for the model of a global group", content_model 173 ) 174 if 'maxOccurs' in content_model.attrib: 175 self.parse_error( 176 "attribute 'maxOccurs' not allowed for the model of a global group", content_model 177 ) 178 if content_model.tag not in {XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}: 179 self.parse_error('unexpected tag %r' % content_model.tag, content_model) 180 return 181 182 else: 183 self.parse_error("found both attributes 'name' and 'ref'") 184 return 185 elif elem.tag in {XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}: 186 # Local group (sequence|all|choice) 187 if 'name' in elem.attrib: 188 self.parse_error("attribute 'name' not allowed for a local group") 189 content_model = elem 190 self.name = None 191 elif elem.tag in {XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_RESTRICTION}: 192 self.name = self.model = None 193 return 194 else: 195 self.parse_error('unexpected tag %r' % elem.tag, elem) 196 return 197 198 self._parse_content_model(elem, content_model)
199
200 - def _parse_content_model(self, elem, content_model):
201 self.model = local_name(content_model.tag) 202 if self.model == 'all': 203 if self.max_occurs != 1: 204 self.parse_error("maxOccurs must be 1 for 'all' model groups") 205 if self.min_occurs not in (0, 1): 206 self.parse_error("minOccurs must be (0 | 1) for 'all' model groups") 207 208 for child in self._iterparse_components(content_model): 209 if child.tag == XSD_ELEMENT: 210 # Builds inner elements and reference groups later, for avoids circularity. 211 self.append((child, self.schema)) 212 elif content_model.tag == XSD_ALL: 213 self.parse_error("'all' model can contains only elements.", elem) 214 elif child.tag == XSD_ANY: 215 self.append(XsdAnyElement(child, self.schema, self)) 216 elif child.tag in (XSD_SEQUENCE, XSD_CHOICE): 217 self.append(XsdGroup(child, self.schema, self)) 218 elif child.tag == XSD_GROUP: 219 try: 220 ref = self.schema.resolve_qname(child.attrib['ref']) 221 except KeyError: 222 self.parse_error("missing attribute 'ref' in local group", child) 223 continue 224 225 if ref != self.name: 226 xsd_group = XsdGroup(child, self.schema, self) 227 if xsd_group.model == 'all': 228 self.parse_error("'all' model can appears only at 1st level of a model group") 229 else: 230 self.append(xsd_group) 231 elif self.redefine is None: 232 self.parse_error("Circular definition detected for group %r:" % self.ref, elem) 233 else: 234 if child.get('minOccurs', '1') != '1' or child.get('maxOccurs', '1') != '1': 235 self.parse_error( 236 "Redefined group reference cannot have minOccurs/maxOccurs other than 1:", elem 237 ) 238 self.append(self.redefine) 239 else: 240 continue # Error already caught by validation against the meta-schema
241
242 - def children_validation_error(self, validation, elem, index, particle, occurs=0, expected=None, 243 source=None, namespaces=None, **_kwargs):
244 """ 245 Helper method for generating model validation errors. Incompatible with 'skip' validation mode. 246 Il validation mode is 'lax' returns the error, otherwise raise the error. 247 248 :param validation: the validation mode. Can be 'lax' or 'strict'. 249 :param elem: the instance Element. 250 :param index: the child index. 251 :param particle: the XSD component (subgroup or element) associated to the child. 252 :param occurs: the child tag occurs. 253 :param expected: the expected element tags/object names. 254 :param source: the XML resource related to the validation process. 255 :param namespaces: is an optional mapping from namespace prefix to URI. 256 :param _kwargs: keyword arguments of the validation process that are not used. 257 """ 258 if validation == 'skip': 259 raise XMLSchemaValueError("validation mode 'skip' incompatible with error generation.") 260 261 error = XMLSchemaChildrenValidationError(self, elem, index, particle, occurs, expected, source, namespaces) 262 if validation == 'strict': 263 raise error 264 else: 265 return error
266
267 - def build(self):
268 element_class = self.schema.BUILDERS.element_class 269 for k in range(len(self._group)): 270 if isinstance(self._group[k], tuple): 271 elem, schema = self._group[k] 272 self._group[k] = element_class(elem, schema, self) 273 274 if self.redefine is not None: 275 for group in self.redefine.iter_components(XsdGroup): 276 group.build()
277 278 @property
279 - def built(self):
280 for item in self: 281 if not isinstance(item, ParticleMixin): 282 return False 283 elif isinstance(item, XsdAnyElement): 284 if not item.built: 285 return False 286 elif item.parent is None: 287 continue 288 elif item.parent is not self.parent and isinstance(item.parent, XsdType) and item.parent.parent is None: 289 continue 290 elif not item.ref and not item.built: 291 return False 292 return True
293 294 @property
295 - def schema_elem(self):
296 return self.elem if self.name else self.parent.elem
297 298 @property
299 - def validation_attempted(self):
300 if self.built: 301 return 'full' 302 elif any([item.validation_attempted == 'partial' for item in self]): 303 return 'partial' 304 else: 305 return 'none'
306 307 @property
308 - def ref(self):
309 return self.elem.get('ref')
310
311 - def iter_components(self, xsd_classes=None):
312 if xsd_classes is None or isinstance(self, xsd_classes): 313 yield self 314 for item in self: 315 if item.parent is None: 316 continue 317 elif item.parent is not self.parent and isinstance(item.parent, XsdType) and item.parent.parent is None: 318 continue 319 for obj in item.iter_components(xsd_classes): 320 yield obj
321
322 - def admitted_restriction(self, model):
323 if self.model == model: 324 return True 325 elif self.model == 'all' and model == 'choice' and len(self) > 1: 326 return False 327 elif model == 'all' and self.model == 'choice' and len(self) > 1: 328 return False 329 if model == 'sequence' and self.model != 'sequence' and len(self) > 1: 330 return False
331
332 - def is_empty(self):
333 return not self.mixed and not self
334
335 - def is_restriction(self, other, check_occurs=True):
336 if not self: 337 return True 338 elif self.ref is not None: 339 return self[0].is_restriction(other, check_occurs) 340 elif not isinstance(other, ParticleMixin): 341 raise XMLSchemaValueError("the argument 'base' must be a %r instance" % ParticleMixin) 342 elif not isinstance(other, XsdGroup): 343 return self.is_element_restriction(other) 344 elif not other: 345 return False 346 elif other.ref: 347 return self.is_restriction(other[0], check_occurs) 348 elif len(other) == other.min_occurs == other.max_occurs == 1: 349 if len(self) > 1: 350 return self.is_restriction(other[0], check_occurs) 351 elif isinstance(self[0], XsdGroup) and self[0].is_pointless(parent=self): 352 return self[0].is_restriction(other[0], check_occurs) 353 354 # Compare model with model 355 if self.model != other.model and self.model != 'sequence' and len(self) > 1: 356 return False 357 elif self.model == other.model or other.model == 'sequence': 358 return self.is_sequence_restriction(other) 359 elif other.model == 'all': 360 return self.is_all_restriction(other) 361 elif other.model == 'choice': 362 return self.is_choice_restriction(other)
363
364 - def is_element_restriction(self, other):
365 if self.schema.XSD_VERSION == '1.0' and isinstance(other, XsdElement) and \ 366 not other.ref and other.name not in self.schema.substitution_groups: 367 return False 368 elif not self.has_occurs_restriction(other): 369 return False 370 elif self.model == 'choice': 371 if other.name in self.maps.substitution_groups and all( 372 isinstance(e, XsdElement) and e.substitution_group == other.name for e in self): 373 return True 374 return any(e.is_restriction(other, False) for e in self) 375 else: 376 min_occurs = max_occurs = 0 377 for item in self.iter_model(): 378 if isinstance(item, XsdGroup): 379 return False 380 elif item.min_occurs == 0 or item.is_restriction(other, False): 381 min_occurs += item.min_occurs 382 if max_occurs is not None: 383 if item.max_occurs is None: 384 max_occurs = None 385 else: 386 max_occurs += item.max_occurs 387 continue 388 return False 389 390 if min_occurs < other.min_occurs: 391 return False 392 elif max_occurs is None: 393 return other.max_occurs is None 394 elif other.max_occurs is None: 395 return True 396 else: 397 return max_occurs <= other.max_occurs
398
399 - def is_sequence_restriction(self, other):
400 if not self.has_occurs_restriction(other): 401 return False 402 check_occurs = other.max_occurs != 0 403 check_emptiable = other.model != 'choice' # or self.schema.XSD_VERSION == '1.0' 404 405 # Same model: declarations must simply preserve order 406 other_iterator = iter(other.iter_model()) 407 for item in self.iter_model(): 408 while True: 409 try: 410 other_item = next(other_iterator) 411 except StopIteration: 412 return False 413 if other_item is item or item.is_restriction(other_item, check_occurs): 414 break 415 elif check_emptiable and not other_item.is_emptiable(): 416 return False 417 418 if not check_emptiable: 419 return True 420 421 while True: 422 try: 423 other_item = next(other_iterator) 424 except StopIteration: 425 return True 426 else: 427 if not other_item.is_emptiable(): 428 return False
429
430 - def is_all_restriction(self, other):
431 if not self.has_occurs_restriction(other): 432 return False 433 434 check_occurs = other.max_occurs != 0 435 restriction_items = list(self) 436 437 for other_item in other.iter_model(): 438 for item in restriction_items: 439 if other_item is item or item.is_restriction(other_item, check_occurs): 440 break 441 else: 442 if not other_item.is_emptiable(): 443 return False 444 continue 445 restriction_items.remove(item) 446 447 return not bool(restriction_items)
448
449 - def is_choice_restriction(self, other):
450 if self.parent is None and other.parent is not None and self.schema.XSD_VERSION == '1.0': 451 return False 452 453 check_occurs = other.max_occurs != 0 454 restriction_items = list(self) 455 max_occurs = 0 456 other_max_occurs = 0 457 458 for other_item in other.iter_model(): 459 for item in restriction_items: 460 461 if other_item is item or item.is_restriction(other_item, check_occurs): 462 if max_occurs is not None: 463 if item.max_occurs is None: 464 max_occurs = None 465 else: 466 max_occurs += item.max_occurs 467 468 if other_max_occurs is not None: 469 if other_item.max_occurs is None: 470 other_max_occurs = None 471 else: 472 other_max_occurs = max(other_max_occurs, other_item.max_occurs) 473 break 474 else: 475 continue 476 restriction_items.remove(item) 477 478 if restriction_items: 479 return False 480 elif other_max_occurs is None: 481 if other.max_occurs: 482 return True 483 other_max_occurs = 0 484 elif other.max_occurs is None: 485 if other_max_occurs: 486 return True 487 other_max_occurs = 0 488 else: 489 other_max_occurs *= other.max_occurs 490 491 if max_occurs is None: 492 return self.max_occurs == 0 493 elif self.max_occurs is None: 494 return max_occurs == 0 495 else: 496 return other_max_occurs >= max_occurs * self.max_occurs
497
498 - def iter_elements(self, depth=0):
499 if depth <= MAX_MODEL_DEPTH: 500 for item in self: 501 if isinstance(item, XsdGroup): 502 for e in item.iter_elements(depth+1): 503 yield e 504 else: 505 yield item 506 for e in self.maps.substitution_groups.get(item.name, ()): 507 yield e
508
509 - def sort_children(self, elements, default_namespace=None):
510 """ 511 Sort elements by group order, that maybe partial in case of 'all' or 'choice' ordering. 512 The not matching elements are appended at the end. 513 """ 514 def sorter(elem): 515 for e in elements_order: 516 if e.is_matching(elem.tag, default_namespace): 517 return elements_order[e] 518 return len(elements_order)
519 520 elements_order = {e: p for p, e in enumerate(self.iter_elements())} 521 return sorted(elements, key=sorter)
522
523 - def iter_decode(self, elem, validation='lax', converter=None, **kwargs):
524 """ 525 Creates an iterator for decoding an Element content. 526 527 :param elem: the Element that has to be decoded. 528 :param validation: the validation mode, can be 'lax', 'strict' or 'skip. 529 :param converter: an :class:`XMLSchemaConverter` subclass or instance. 530 :param kwargs: keyword arguments for the decoding process. 531 :return: yields a list of 3-tuples (key, decoded data, decoder), eventually \ 532 preceded by a sequence of validation or decoding errors. 533 """ 534 def not_whitespace(s): 535 return s is not None and s.strip()
536 537 result_list = [] 538 cdata_index = 1 # keys for CDATA sections are positive integers 539 540 if validation != 'skip' and not self.mixed: 541 # Check element CDATA 542 if not_whitespace(elem.text) or any([not_whitespace(child.tail) for child in elem]): 543 if len(self) == 1 and isinstance(self[0], XsdAnyElement): 544 pass # [XsdAnyElement()] is equivalent to an empty complexType declaration 545 else: 546 reason = "character data between child elements not allowed!" 547 yield self.validation_error(validation, reason, elem, **kwargs) 548 cdata_index = 0 # Do not decode CDATA 549 550 if cdata_index and elem.text is not None: 551 text = unicode_type(elem.text.strip()) 552 if text: 553 result_list.append((cdata_index, text, None)) 554 cdata_index += 1 555 556 model = ModelVisitor(self) 557 errors = [] 558 559 if not isinstance(converter, XMLSchemaConverter): 560 converter = self.schema.get_converter(converter, **kwargs) 561 default_namespace = converter.get('') 562 563 for index, child in enumerate(elem): 564 if callable(child.tag): 565 continue # child is a <class 'lxml.etree._Comment'> 566 567 if not default_namespace or child.tag[0] == '{': 568 tag = child.tag 569 else: 570 tag = '{%s}%s' % (default_namespace, child.tag) 571 572 while model.element is not None: 573 if tag in model.element.names or model.element.name is None \ 574 and model.element.is_matching(tag, default_namespace): 575 xsd_element = model.element 576 else: 577 for xsd_element in model.element.iter_substitutes(): 578 if tag in xsd_element.names: 579 break 580 else: 581 for particle, occurs, expected in model.advance(False): 582 errors.append((index, particle, occurs, expected)) 583 model.clear() 584 model.broken = True # the model is broken, continues with raw decoding. 585 break 586 continue 587 588 for particle, occurs, expected in model.advance(True): 589 errors.append((index, particle, occurs, expected)) 590 break 591 else: 592 for xsd_element in self.iter_elements(): 593 if tag in xsd_element.names or xsd_element.name is None \ 594 and xsd_element.is_matching(child.tag, default_namespace): 595 if not model.broken: 596 model.broken = True 597 errors.append((index, xsd_element, 0, [])) 598 break 599 else: 600 errors.append((index, self, 0, None)) 601 xsd_element = None 602 if not model.broken: 603 model.broken = True 604 605 if xsd_element is None: 606 # TODO: use a default decoder str-->str?? 607 continue 608 609 for result in xsd_element.iter_decode(child, validation, converter, **kwargs): 610 if isinstance(result, XMLSchemaValidationError): 611 yield result 612 else: 613 result_list.append((child.tag, result, xsd_element)) 614 615 if cdata_index and child.tail is not None: 616 tail = unicode_type(child.tail.strip()) 617 if tail: 618 if result_list and isinstance(result_list[-1][0], int): 619 tail = result_list[-1][1] + ' ' + tail 620 result_list[-1] = result_list[-1][0], tail, None 621 else: 622 result_list.append((cdata_index, tail, None)) 623 cdata_index += 1 624 625 if model.element is not None: 626 index = len(elem) 627 for particle, occurs, expected in model.stop(): 628 errors.append((index, particle, occurs, expected)) 629 630 if validation != 'skip' and errors: 631 for model_error in errors: 632 yield self.children_validation_error(validation, elem, *model_error, **kwargs) 633 634 yield result_list 635
636 - def iter_encode(self, element_data, validation='lax', converter=None, **kwargs):
637 """ 638 Creates an iterator for encoding data to a list containing Element data. 639 640 :param element_data: an ElementData instance with unencoded data. 641 :param validation: the validation mode: can be 'lax', 'strict' or 'skip'. 642 :param converter: an :class:`XMLSchemaConverter` subclass or instance. 643 :param kwargs: Keyword arguments for the encoding process. 644 :return: Yields a couple with the text of the Element and a list of 3-tuples \ 645 (key, decoded data, decoder), eventually preceded by a sequence of validation \ 646 or encoding errors. 647 """ 648 if not element_data.content: # <tag/> or <tag></tag> 649 yield element_data.content 650 return 651 652 if not isinstance(converter, XMLSchemaConverter): 653 converter = self.schema.get_converter(converter, **kwargs) 654 655 errors = [] 656 text = None 657 children = [] 658 level = kwargs.get('level', 0) 659 indent = kwargs.get('indent', 4) 660 padding = '\n' + ' ' * indent * level 661 default_namespace = converter.get('') 662 losslessly = converter.losslessly 663 664 model = ModelVisitor(self) 665 cdata_index = 0 666 667 for index, (name, value) in enumerate(element_data.content): 668 if isinstance(name, int): 669 if not children: 670 text = padding + value if text is None else text + value + padding 671 elif children[-1].tail is None: 672 children[-1].tail = padding + value 673 else: 674 children[-1].tail += value + padding 675 cdata_index += 1 676 continue 677 678 if not default_namespace or name[0] == '{': 679 tag = name 680 else: 681 tag = '{%s}%s' % (default_namespace, name) 682 683 while model.element is not None: 684 if tag in model.element.names or model.element.name is None \ 685 and model.element.is_matching(tag, default_namespace): 686 xsd_element = model.element 687 else: 688 for xsd_element in model.element.iter_substitutes(): 689 if tag in xsd_element.names: 690 break 691 else: 692 for particle, occurs, expected in model.advance(): 693 errors.append((index - cdata_index, particle, occurs, expected)) 694 continue 695 696 if isinstance(xsd_element, XsdAnyElement): 697 value = get_qname(default_namespace, name), value 698 for result in xsd_element.iter_encode(value, validation, converter, **kwargs): 699 if isinstance(result, XMLSchemaValidationError): 700 yield result 701 else: 702 children.append(result) 703 704 for particle, occurs, expected in model.advance(True): 705 errors.append((index - cdata_index, particle, occurs, expected)) 706 break 707 else: 708 if losslessly: 709 errors.append((index - cdata_index, self, 0, [])) 710 711 for xsd_element in self.iter_elements(): 712 if tag in xsd_element.names or xsd_element.name is None \ 713 and xsd_element.is_matching(name, default_namespace): 714 if isinstance(xsd_element, XsdAnyElement): 715 value = get_qname(default_namespace, name), value 716 for result in xsd_element.iter_encode(value, validation, converter, **kwargs): 717 if isinstance(result, XMLSchemaValidationError): 718 yield result 719 else: 720 children.append(result) 721 break 722 else: 723 if validation != 'skip': 724 reason = '%r does not match any declared element of the model group.' % name 725 yield self.validation_error(validation, reason, value, **kwargs) 726 727 if model.element is not None: 728 index = len(element_data.content) - cdata_index 729 for particle, occurs, expected in model.stop(): 730 errors.append((index, particle, occurs, expected)) 731 732 # If the validation is not strict tries to solve model errors with a reorder of the children 733 if errors and validation != 'strict': 734 children = self.sort_children(children, default_namespace) 735 736 if children: 737 if children[-1].tail is None: 738 children[-1].tail = padding[:-indent] or '\n' 739 else: 740 children[-1].tail = children[-1].tail.strip() + (padding[:-indent] or '\n') 741 742 if validation != 'skip' and errors: 743 attrib = {k: unicode_type(v) for k, v in element_data.attributes.items()} 744 if validation == 'lax' and converter.etree_element_class is not etree_element: 745 child_tags = [converter.etree_element(e.tag, attrib=e.attrib) for e in children] 746 elem = converter.etree_element(element_data.tag, text, child_tags, attrib) 747 else: 748 elem = converter.etree_element(element_data.tag, text, children, attrib) 749 750 for index, particle, occurs, expected in errors: 751 yield self.children_validation_error(validation, elem, index, particle, occurs, expected, **kwargs) 752 753 yield text, children
754
755 - def update_occurs(self, counter):
756 """ 757 Update group occurrences. 758 759 :param counter: a Counter object that trace occurrences for elements and groups. 760 """ 761 if self.model in ('sequence', 'all'): 762 if all(counter[item] for item in self if not item.is_emptiable()): 763 counter[self] += 1 764 for item in self: 765 counter[item] = 0 766 elif self.model == 'choice': 767 if any(counter[item] for item in self): 768 counter[self] += 1 769 for item in self: 770 counter[item] = 0 771 else: 772 raise XMLSchemaValueError("the group %r has no model!" % self)
773
774 775 -class Xsd11Group(XsdGroup):
776 """ 777 A class for XSD 1.1 model group definitions. The XSD 1.1 model groups differ 778 from XSD 1.0 groups for the 'all' model, that can contains also other groups. 779 780 <all 781 id = ID 782 maxOccurs = (0 | 1) : 1 783 minOccurs = (0 | 1) : 1 784 {any attributes with non-schema namespace . . .}> 785 Content: (annotation?, (element | any | group)*) 786 </all> 787 """
788 - def _parse_content_model(self, elem, content_model):
789 self.model = local_name(content_model.tag) 790 if self.model == 'all': 791 if self.max_occurs != 1: 792 self.parse_error("maxOccurs must be (0 | 1) for 'all' model groups") 793 if self.min_occurs not in (0, 1): 794 self.parse_error("minOccurs must be (0 | 1) for 'all' model groups") 795 796 for child in self._iterparse_components(content_model): 797 if child.tag == XSD_ELEMENT: 798 # Builds inner elements and reference groups later, for avoids circularity. 799 self.append((child, self.schema)) 800 elif child.tag == XSD_ANY: 801 self.append(XsdAnyElement(child, self.schema, self)) 802 elif child.tag in (XSD_SEQUENCE, XSD_CHOICE, XSD_ALL): 803 self.append(XsdGroup(child, self.schema, self)) 804 elif child.tag == XSD_GROUP: 805 try: 806 ref = self.schema.resolve_qname(child.attrib['ref']) 807 except KeyError: 808 self.parse_error("missing attribute 'ref' in local group", child) 809 continue 810 811 if ref != self.name: 812 self.append(XsdGroup(child, self.schema, self)) 813 elif self.redefine is None: 814 self.parse_error("Circular definition detected for group %r:" % self.ref, elem) 815 else: 816 if child.get('minOccurs', '1') != '1' or child.get('maxOccurs', '1') != '1': 817 self.parse_error( 818 "Redefined group reference cannot have minOccurs/maxOccurs other than 1:", elem 819 ) 820 self.append(self.redefine) 821 else: 822 continue # Error already caught by validation against the meta-schema
823