Fix 'all' model groups visiting

- Also at each match the group element is changed (TODO: check if
    it's better to restart like choice groups)
  - In XSD 1.1 __iter__ now yields wildcards at the end for 'all'
    and 'choice' model groups
This commit is contained in:
Davide Brunato 2019-10-30 07:13:47 +01:00
parent 732864edc7
commit 2b1497860b
3 changed files with 69 additions and 3 deletions

View File

@ -15,13 +15,15 @@ This module runs tests concerning model groups validation.
import unittest
from xmlschema import XMLSchema10, XMLSchema11
from xmlschema.validators import ModelVisitor
from xmlschema.validators import XsdElement, ModelVisitor
from xmlschema.compat import ordered_dict_class
from xmlschema.tests import casepath, XsdValidatorTestCase
class TestModelValidation(XsdValidatorTestCase):
schema_class = XMLSchema10
# --- Test helper functions ---
def check_advance_true(self, model, expected=None):
@ -514,6 +516,32 @@ class TestModelValidation(XsdValidatorTestCase):
self.check_advance_true(model) # match choice with <elem4>
self.assertIsNone(model.element)
def test_empty_choice_groups(self):
schema = self.schema_class("""<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:group name="group1">
<xs:sequence>
<xs:choice minOccurs="0">
<xs:choice minOccurs="0"/>
</xs:choice>
<xs:element name="elem1"/>
</xs:sequence>
</xs:group>
<xs:element name="root">
<xs:complexType>
<xs:choice>
<xs:group ref="group1"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>""")
xml_data = "<root><elem1/></root>"
model = ModelVisitor(schema.elements['root'].type.content_type)
self.assertIsInstance(model.element, XsdElement)
self.assertEqual(model.element.name, 'elem1')
self.assertIsNone(schema.validate(xml_data))
#
# Tests on issues
def test_issue_086(self):
@ -576,6 +604,32 @@ class TestModelValidation(XsdValidatorTestCase):
class TestModelValidation11(TestModelValidation):
schema_class = XMLSchema11
def test_all_model_with_wildcard(self):
schema = self.schema_class(
"""<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="a" type="xs:string" />
<xs:any maxOccurs="3" processContents="lax" />
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
""")
xml_data = """
<root>
<wildcard1/>
<a>1</a>
<wildcard2/>
<wildcard3/>
</root>
"""
self.assertIsNone(schema.validate(xml_data))
class TestModelBasedSorting(XsdValidatorTestCase):

View File

@ -821,6 +821,11 @@ class Xsd11Group(XsdGroup):
Content: (annotation?, (element | any | group)*)
</all>
"""
def __iter__(self):
if self.model == 'sequence':
return iter(self._group)
return iter(sorted(self._group, key=lambda x: isinstance(x, XsdAnyElement)))
def _parse_content_model(self, content_model):
self.model = local_name(content_model.tag)
if self.model == 'all':

View File

@ -379,7 +379,12 @@ class ModelVisitor(MutableSequence):
def _start(self):
while True:
item = next(self.items, None)
if item is None or not isinstance(item, ModelGroup):
if item is None:
if not self:
break
else:
self.group, self.items, self.match = self.pop()
elif not isinstance(item, ModelGroup):
self.element = item
break
elif item:
@ -464,7 +469,9 @@ class ModelVisitor(MutableSequence):
if match:
occurs[element] += 1
self.match = True
if not element.is_over(occurs[element]):
if self.group.model == 'all':
pass
elif not element.is_over(occurs[element]):
return
obj = None