Skip to content

Commit

Permalink
Ignore xsi:type with meta-schema validation (issue #350)
Browse files Browse the repository at this point in the history
  • Loading branch information
brunato committed Jun 12, 2023
1 parent 497cb5c commit 9a78cf3
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 10 deletions.
2 changes: 1 addition & 1 deletion tests/test_documents.py
Expand Up @@ -196,7 +196,7 @@ def test_get_context_without_schema(self):

source, schema = get_context(xml_data)
self.assertIsInstance(source, XMLResource)
self.assertIs(schema, XMLSchema10.meta_schema)
self.assertIsNot(schema, XMLSchema10.meta_schema)
self.assertEqual(source.root.tag, 'text')
self.assertTrue(schema.is_valid(source))

Expand Down
27 changes: 27 additions & 0 deletions tests/validation/test_validation.py
Expand Up @@ -328,6 +328,33 @@ def test_issue_238__validate_bytes_strings(self):
self.assertIsInstance(col_xml_data, bytes)
self.assertTrue(self.col_schema.is_valid(col_xml_data))

def test_issue_350__ignore_xsi_type_for_schema_validation(self):
schema = xmlschema.XMLSchema(dedent("""\
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xs:element name="root" xsi:type="non-empty-string" />
<xs:simpleType name="non-empty-string">
<xs:restriction base="xs:string">
<xs:minLength value="1" />
</xs:restriction>
</xs:simpleType>
</xs:schema>"""))

self.assertTrue(schema.is_valid('<root></root>'))
self.assertTrue(schema.is_valid('<root>foo</root>'))

self.assertFalse(schema.is_valid(
'<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
'xsi:type="non-empty-string"></root>'
))
self.assertTrue(schema.is_valid(
'<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
'xsi:type="non-empty-string">foo</root>'
))


class TestValidation11(TestValidation):
schema_class = XMLSchema11
Expand Down
10 changes: 5 additions & 5 deletions xmlschema/documents.py
Expand Up @@ -74,10 +74,10 @@ def get_context(xml_document: Union[XMLSourceType, XMLResource],
return resource, cls(schema, **kwargs)

if schema is None:
if cls.meta_schema is not None and \
(XSI_TYPE in resource.root.attrib or XSD_NAMESPACE in resource.namespace):
if XSD_NAMESPACE == resource.namespace:
assert cls.meta_schema is not None
return resource, cls.meta_schema
elif dummy_schema:
elif dummy_schema or XSI_TYPE in resource.root.attrib:
return resource, get_dummy_schema(resource.root.tag, cls)
else:
msg = "cannot get a schema for XML data, provide a schema argument"
Expand Down Expand Up @@ -602,12 +602,12 @@ def __init__(self, source: XMLSourceType,

if self.schema is None:
if XSI_TYPE in self._root.attrib:
self.schema = cls.meta_schema
self.schema = get_dummy_schema(self._root.tag, cls)
elif validation != 'skip':
msg = "cannot get a schema for XML data, provide a schema argument"
raise XMLSchemaValueError(msg)
else:
self._fallback_schema = get_dummy_schema(self.root.tag, cls)
self._fallback_schema = get_dummy_schema(self._root.tag, cls)

if self.schema is None:
pass
Expand Down
5 changes: 3 additions & 2 deletions xmlschema/validators/elements.py
Expand Up @@ -657,7 +657,8 @@ def iter_decode(self, obj: ElementType, validation: str = 'lax', **kwargs: Any)

# Get the instance effective type
xsd_type = self.get_type(obj, inherited)
if XSI_TYPE in obj.attrib:
if XSI_TYPE in obj.attrib and self.schema.meta_schema is not None:
# Meta-schema elements ignore xsi:type (issue #350)
type_name = obj.attrib[XSI_TYPE].strip()
try:
xsd_type = self.maps.get_instance_type(type_name, xsd_type, namespaces)
Expand Down Expand Up @@ -974,7 +975,7 @@ def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \
attributes = ()

xsd_type = self.get_type(element_data)
if XSI_TYPE in element_data.attributes:
if XSI_TYPE in element_data.attributes and self.schema.meta_schema is not None:
type_name = element_data.attributes[XSI_TYPE].strip()
try:
xsd_type = self.maps.get_instance_type(type_name, xsd_type, converter)
Expand Down
8 changes: 6 additions & 2 deletions xmlschema/validators/groups.py
Expand Up @@ -804,6 +804,10 @@ def check_dynamic_context(self, elem: ElementType,
try:
xsd_element = self.maps.lookup_element(elem.tag)
except LookupError:
if self.schema.meta_schema is None:
# Meta-schema groups ignore xsi:type (issue #350)
return

try:
type_name = elem.attrib[XSI_TYPE].strip()
except KeyError:
Expand All @@ -824,7 +828,7 @@ def check_dynamic_context(self, elem: ElementType,
)

else:
if XSI_TYPE not in elem.attrib:
if XSI_TYPE not in elem.attrib or self.schema.meta_schema is None:
xsd_type = xsd_element.type
else:
alternatives = xsd_element.alternatives
Expand All @@ -846,7 +850,7 @@ def check_dynamic_context(self, elem: ElementType,
"head element").format(xsd_element, derivation)
raise XMLSchemaValidationError(self, elem, reason)

if XSI_TYPE not in elem.attrib:
if XSI_TYPE not in elem.attrib or self.schema.meta_schema is None:
return

# If it's a restriction the context is the base_type's group
Expand Down

0 comments on commit 9a78cf3

Please sign in to comment.