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:
parent
732864edc7
commit
2b1497860b
|
@ -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):
|
||||
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue