Add minimal schema for versioning namespace

- Added XMLSchemaNamespaceError for namespace related errors
  - version_check moved to schema class
  - resolve_qname() now raises KeyError if namespace prefix is not found
  - resolve_qname() now raises XMLSchemaNamespaceError if a namespace
    is mapped with a prefix but is not loaded by an import
This commit is contained in:
Davide Brunato 2019-08-01 07:03:03 +02:00
parent 6e90de7b4c
commit df5c454b24
16 changed files with 217 additions and 116 deletions

View File

@ -8,7 +8,8 @@
#
# @author Davide Brunato <brunato@sissa.it>
#
from .exceptions import XMLSchemaException, XMLSchemaRegexError, XMLSchemaURLError
from .exceptions import XMLSchemaException, XMLSchemaRegexError, XMLSchemaURLError, \
XMLSchemaNamespaceError
from .resources import (
normalize_url, fetch_resource, load_xml_resource, fetch_namespaces,
fetch_schema_locations, fetch_schema, XMLResource

View File

@ -54,5 +54,9 @@ class XMLSchemaRegexError(XMLSchemaException, ValueError):
"""Raised when an error is found when parsing an XML Schema regular expression."""
class XMLSchemaNamespaceError(XMLSchemaException, RuntimeError):
"""Raised when a wrong runtime condition is found with a namespace."""
class XMLSchemaWarning(Warning):
"""Base warning class for the XMLSchema package."""

View File

@ -23,6 +23,10 @@ XSI_TEMPLATE = '{http://www.w3.org/2001/XMLSchema-instance}%s'
# Version Control attributes (XSD 1.1)
VC_MIN_VERSION = VC_TEMPLATE % 'minVersion'
VC_MAX_VERSION = VC_TEMPLATE % 'maxVersion'
VC_TYPE_AVAILABLE = VC_TEMPLATE % 'typeAvailable'
VC_TYPE_UNAVAILABLE = VC_TEMPLATE % 'typeUnavailable'
VC_FACET_AVAILABLE = VC_TEMPLATE % 'facetAvailable'
VC_FACET_UNAVAILABLE = VC_TEMPLATE % 'facetUnavailable'
#

View File

@ -292,11 +292,11 @@ class TestGlobalMaps(unittest.TestCase):
def test_xsd_11_globals(self):
self.assertEqual(len(XMLSchema11.meta_schema.maps.notations), 2)
self.assertEqual(len(XMLSchema11.meta_schema.maps.types), 118)
self.assertEqual(len(XMLSchema11.meta_schema.maps.attributes), 18)
self.assertEqual(len(XMLSchema11.meta_schema.maps.attributes), 24)
self.assertEqual(len(XMLSchema11.meta_schema.maps.attribute_groups), 10)
self.assertEqual(len(XMLSchema11.meta_schema.maps.groups), 19)
self.assertEqual(len(XMLSchema11.meta_schema.maps.elements), 51)
self.assertEqual(len([e.is_global for e in XMLSchema11.meta_schema.maps.iter_globals()]), 218)
self.assertEqual(len([e.is_global for e in XMLSchema11.meta_schema.maps.iter_globals()]), 224)
self.assertEqual(len(XMLSchema11.meta_schema.maps.substitution_groups), 1)
def test_xsd_10_build(self):
@ -307,7 +307,7 @@ class TestGlobalMaps(unittest.TestCase):
self.assertTrue(XMLSchema10.meta_schema.maps.built)
def test_xsd_11_build(self):
self.assertEqual(len([e for e in XMLSchema11.meta_schema.maps.iter_globals()]), 218)
self.assertEqual(len([e for e in XMLSchema11.meta_schema.maps.iter_globals()]), 224)
self.assertTrue(XMLSchema11.meta_schema.maps.built)
XMLSchema11.meta_schema.maps.clear()
XMLSchema11.meta_schema.maps.build()
@ -332,8 +332,8 @@ class TestGlobalMaps(unittest.TestCase):
total_counter += 1
if c.is_global:
global_counter += 1
self.assertEqual(global_counter, 218)
self.assertEqual(total_counter, 1018)
self.assertEqual(global_counter, 224)
self.assertEqual(total_counter, 1028)
if __name__ == '__main__':

View File

@ -95,7 +95,7 @@ def create_w3c_test_group_case(filename, group_elem, group_number, xsd_version='
if group_elem.get('version') == '1.0':
raise ValueError("testGroup %r is not suited for XSD 1.1" % name)
elif group_elem.get('version') == '1.1':
print(group_elem.attrib)
# print(group_elem.attrib)
if group_elem.get('name') == '002':
breakpoint()
schema_class = xmlschema.XMLSchema11

View File

@ -101,10 +101,10 @@ class XsdAttribute(XsdComponent, ValidationMixin):
for attribute in ('form', 'type'):
if attribute in self.elem.attrib:
self.parse_error("attribute %r is not allowed when attribute reference is used." % attribute)
xsd_declaration = self._parse_child_component(self.elem)
if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE:
self.parse_error("not allowed type declaration for XSD attribute reference")
child = self._parse_child_component(self.elem)
if child is not None and child.tag == XSD_SIMPLE_TYPE:
self.parse_error("not allowed type definition for XSD attribute reference")
return
try:
@ -133,30 +133,30 @@ class XsdAttribute(XsdComponent, ValidationMixin):
else:
self.name = name
xsd_declaration = self._parse_child_component(self.elem)
try:
type_qname = self.schema.resolve_qname(attrib['type'])
except ValueError as err:
self.parse_error(err)
xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
except KeyError:
if xsd_declaration is not None:
# No 'type' attribute in declaration, parse for child local simpleType
xsd_type = self.schema.BUILDERS.simple_type_factory(xsd_declaration, self.schema, self)
else:
# Empty declaration means xsdAnySimpleType
xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
else:
child = self._parse_child_component(self.elem)
if 'type' in attrib:
try:
xsd_type = self.maps.lookup_type(type_qname)
except LookupError as err:
type_qname = self.schema.resolve_qname(attrib['type'])
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err)
xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
else:
try:
xsd_type = self.maps.lookup_type(type_qname)
except LookupError as err:
self.parse_error(err)
xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
if xsd_declaration is not None and xsd_declaration.tag == XSD_SIMPLE_TYPE:
self.parse_error("ambiguous type declaration for XSD attribute")
elif xsd_declaration:
self.parse_error("not allowed element in XSD attribute declaration: %r" % xsd_declaration[0])
if child and child.tag == XSD_SIMPLE_TYPE:
self.parse_error("ambiguous type definition for XSD attribute")
elif child:
self.parse_error("not allowed element in XSD attribute declaration: %r" % child[0])
elif child:
# No 'type' attribute in declaration, parse for child local simpleType
xsd_type = self.schema.BUILDERS.simple_type_factory(child, self.schema, self)
else:
# Empty declaration means xsdAnySimpleType
xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
try:
self.type = xsd_type
@ -394,11 +394,14 @@ class XsdAttributeGroup(MutableMapping, XsdComponent, ValidationMixin):
elif child.tag == XSD_ATTRIBUTE_GROUP:
try:
ref = child.attrib['ref']
attribute_group_qname = self.schema.resolve_qname(ref)
except ValueError as err:
self.parse_error(err, elem)
except KeyError:
self.parse_error("the attribute 'ref' is required in a local attributeGroup", elem)
continue
try:
attribute_group_qname = self.schema.resolve_qname(ref)
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err, elem)
else:
if attribute_group_qname in attribute_group_refs:
self.parse_error("duplicated attributeGroup %r" % ref)

View File

@ -251,11 +251,11 @@ class XsdComplexType(XsdType, ValidationMixin):
def _parse_base_type(self, elem, complex_content=False):
try:
base_qname = self.schema.resolve_qname(elem.attrib['base'])
except KeyError:
self.parse_error("'base' attribute required", elem)
return self.maps.types[XSD_ANY_TYPE]
except ValueError as err:
self.parse_error(err, elem)
except (KeyError, ValueError, RuntimeError) as err:
if 'base' not in elem.attrib:
self.parse_error("'base' attribute required", elem)
else:
self.parse_error(err, elem)
return self.maps.types[XSD_ANY_TYPE]
try:

View File

@ -189,13 +189,16 @@ class XsdElement(XsdComponent, ValidationMixin, ParticleMixin, ElementPathMixin)
self.parse_error("element reference declaration can't has children.")
elif 'type' in attrib:
try:
self.type = self.maps.lookup_type(self.schema.resolve_qname(attrib['type']))
except KeyError:
self.parse_error('unknown type %r' % attrib['type'])
self.type = self.maps.types[XSD_ANY_TYPE]
except ValueError as err:
type_qname = self.schema.resolve_qname(attrib['type'])
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err)
self.type = self.maps.types[XSD_ANY_TYPE]
else:
try:
self.type = self.maps.lookup_type(type_qname)
except KeyError:
self.parse_error('unknown type %r' % attrib['type'])
self.type = self.maps.types[XSD_ANY_TYPE]
finally:
child = self._parse_child_component(self.elem, strict=False)
if child is not None and child.tag in (XSD_COMPLEX_TYPE, XSD_SIMPLE_TYPE):
@ -270,13 +273,13 @@ class XsdElement(XsdComponent, ValidationMixin, ParticleMixin, ElementPathMixin)
self.constraints[constraint.name] = constraint
def _parse_substitution_group(self):
substitution_group = self.elem.get('substitutionGroup')
if substitution_group is None:
if 'substitutionGroup' not in self.elem.attrib:
return
substitution_group = self.elem.attrib['substitutionGroup']
try:
substitution_group_qname = self.schema.resolve_qname(substitution_group)
except ValueError as err:
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err)
return
else:
@ -434,7 +437,7 @@ class XsdElement(XsdComponent, ValidationMixin, ParticleMixin, ElementPathMixin)
:return: yields a decoded object, eventually preceded by a sequence of \
validation or decoding errors.
"""
if not self.version_check(elem):
if not self.schema.version_check(elem):
return
converter = kwargs.get('converter')
@ -870,10 +873,8 @@ class XsdAlternative(XsdComponent):
try:
type_qname = self.schema.resolve_qname(attrib['type'])
except KeyError:
self.parse_error("missing 'type' attribute")
except ValueError as err:
self.parse_error(err)
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err if 'type' in attrib else "missing 'type' attribute")
else:
try:
self.type = self.maps.lookup_type(type_qname)
@ -881,7 +882,8 @@ class XsdAlternative(XsdComponent):
self.parse_error("unknown type %r" % attrib['type'])
else:
if not self.type.is_derived(self.parent.type):
self.parse_error("type %r ir not derived from %r" % (attrib['type'], self.parent.type))
msg = "type {!r} is not derived from {!r}"
self.parse_error(msg.format(attrib['type'], self.parent.type))
@property
def built(self):

View File

@ -511,12 +511,12 @@ class XsdEnumerationFacets(MutableSequence, XsdFacet):
if self.base_type.name == XSD_NOTATION_TYPE:
try:
notation_qname = self.schema.resolve_qname(value)
except ValueError as err:
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err, elem)
else:
if notation_qname not in self.maps.notations:
self.parse_error("value {} must match a notation global declaration".format(value), elem)
msg = "value {!r} must match a notation declaration"
self.parse_error(msg.format(value), elem)
return value
# Implements the abstract methods of MutableSequence

View File

@ -70,7 +70,7 @@ def create_load_function(filter_function):
qname = get_qname(target_namespace, child.attrib['name'])
redefinitions.append((qname, child, schema, schema.includes[location]))
for elem in filter_function(schema.root):
for elem in filter(lambda x: schema.version_check(x), filter_function(schema.root)):
qname = get_qname(target_namespace, elem.attrib['name'])
try:
xsd_globals[qname].append((elem, schema))
@ -430,11 +430,11 @@ class XsdGlobals(XsdValidator):
schema._root_elements = None
# Load and build global declarations
load_xsd_notations(self.notations, not_built_schemas)
load_xsd_simple_types(self.types, not_built_schemas)
load_xsd_complex_types(self.types, not_built_schemas)
load_xsd_notations(self.notations, not_built_schemas)
load_xsd_attributes(self.attributes, not_built_schemas)
load_xsd_attribute_groups(self.attribute_groups, not_built_schemas)
load_xsd_complex_types(self.types, not_built_schemas)
load_xsd_elements(self.elements, not_built_schemas)
load_xsd_groups(self.groups, not_built_schemas)

View File

@ -16,9 +16,8 @@ from __future__ import unicode_literals
from ..compat import unicode_type
from ..exceptions import XMLSchemaValueError
from ..etree import etree_element
from ..qnames import VC_MIN_VERSION, VC_MAX_VERSION, XSD_ANNOTATION, XSD_GROUP, \
XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_COMPLEX_TYPE, XSD_ELEMENT, XSD_ANY, \
XSD_RESTRICTION, XSD_EXTENSION
from ..qnames import XSD_ANNOTATION, XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, \
XSD_COMPLEX_TYPE, XSD_ELEMENT, XSD_ANY, XSD_RESTRICTION, XSD_EXTENSION
from xmlschema.helpers import get_qname, local_name
from ..converters import XMLSchemaConverter
@ -208,8 +207,11 @@ class XsdGroup(XsdComponent, ModelGroup, ValidationMixin):
elif child.tag == XSD_GROUP:
try:
ref = self.schema.resolve_qname(child.attrib['ref'])
except KeyError:
self.parse_error("missing attribute 'ref' in local group", child)
except (KeyError, ValueError, RuntimeError) as err:
if 'ref' not in child.attrib:
self.parse_error("missing attribute 'ref' in local group", child)
else:
self.parse_error(err, child)
continue
if ref != self.name:
@ -532,7 +534,7 @@ class XsdGroup(XsdComponent, ModelGroup, ValidationMixin):
if callable(child.tag):
continue # child is a <class 'lxml.etree._Comment'>
if not self.version_check(child):
if not self.schema.version_check(child):
continue
if self.interleave and self.interleave.is_matching(child.tag, default_namespace, self):
@ -742,8 +744,11 @@ class Xsd11Group(XsdGroup):
elif child.tag == XSD_GROUP:
try:
ref = self.schema.resolve_qname(child.attrib['ref'])
except KeyError:
self.parse_error("missing attribute 'ref' in local group", child)
except (KeyError, ValueError, RuntimeError) as err:
if 'ref' not in child.attrib:
self.parse_error("missing attribute 'ref' in local group", child)
else:
self.parse_error(err, child)
continue
if ref != self.name:

View File

@ -172,7 +172,8 @@ class XsdIdentity(XsdComponent):
"""
current_path = ''
xsd_fields = None
for e in self.selector.xpath_selector.iter_select(elem):
for e in filter(lambda x: self.schema.version_check(x),
self.selector.xpath_selector.iter_select(elem)):
path = etree_getpath(e, elem)
if current_path != path:
# Change the XSD context only if the path is changed
@ -240,10 +241,11 @@ class XsdKeyref(XsdIdentity):
super(XsdKeyref, self)._parse()
try:
self.refer = self.schema.resolve_qname(self.elem.attrib['refer'])
except KeyError:
self.parse_error("missing required attribute 'refer'")
except ValueError as err:
self.parse_error(err)
except (KeyError, ValueError, RuntimeError) as err:
if 'refer' not in self.elem.attrib:
self.parse_error("missing required attribute 'refer'")
else:
self.parse_error(err)
def parse_refer(self):
if self.refer is None:

View File

@ -19,15 +19,19 @@ import os
from collections import namedtuple, Counter
from abc import ABCMeta
import warnings
import re
from ..compat import add_metaclass
from ..exceptions import XMLSchemaTypeError, XMLSchemaURLError, XMLSchemaValueError, XMLSchemaOSError
from ..qnames import XSD_SCHEMA, XSD_ANNOTATION, XSD_NOTATION, XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, \
XSD_GROUP, XSD_SIMPLE_TYPE, XSD_COMPLEX_TYPE, XSD_ELEMENT, XSD_SEQUENCE, XSD_ANY, \
from ..exceptions import XMLSchemaTypeError, XMLSchemaURLError, XMLSchemaKeyError, \
XMLSchemaValueError, XMLSchemaOSError, XMLSchemaNamespaceError
from ..qnames import VC_MIN_VERSION, VC_MAX_VERSION, VC_TYPE_AVAILABLE, \
VC_TYPE_UNAVAILABLE, VC_FACET_AVAILABLE, VC_FACET_UNAVAILABLE, XSD_SCHEMA, \
XSD_ANNOTATION, XSD_NOTATION, XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_GROUP, \
XSD_SIMPLE_TYPE, XSD_COMPLEX_TYPE, XSD_ELEMENT, XSD_SEQUENCE, XSD_ANY, \
XSD_ANY_ATTRIBUTE, XSD_REDEFINE, XSD_OVERRIDE, XSD_DEFAULT_OPEN_CONTENT
from ..helpers import get_xsd_derivation_attribute, get_xsd_form_attribute
from ..namespaces import XSD_NAMESPACE, XML_NAMESPACE, XSI_NAMESPACE, XHTML_NAMESPACE, \
XLINK_NAMESPACE, NamespaceResourcesMap, NamespaceView
XLINK_NAMESPACE, VC_NAMESPACE, NamespaceResourcesMap, NamespaceView
from ..etree import etree_element, etree_tostring, ParseError
from ..resources import is_remote_url, url_path_is_file, fetch_resource, XMLResource
from ..converters import XMLSchemaConverter
@ -49,6 +53,7 @@ from .wildcards import XsdAnyElement, XsdAnyAttribute, Xsd11AnyElement, \
from .globals_ import iterchildren_xsd_import, iterchildren_xsd_include, \
iterchildren_xsd_redefine, iterchildren_xsd_override, XsdGlobals
XSD_VERSION_PATTERN = re.compile(r'\d+\.\d+')
# Elements for building dummy groups
ATTRIBUTE_GROUP_ELEMENT = etree_element(XSD_ATTRIBUTE_GROUP)
@ -67,9 +72,9 @@ ANY_ELEMENT = etree_element(
SCHEMAS_DIR = os.path.join(os.path.dirname(__file__), 'schemas/')
XML_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'xml_minimal.xsd')
HFP_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'XMLSchema-hasFacetAndProperty_minimal.xsd')
XSI_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'XMLSchema-instance_minimal.xsd')
XLINK_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'xlink.xsd')
VC_SCHEMA_FILE = os.path.join(SCHEMAS_DIR, 'XMLSchema-versioning_minimal.xsd')
class XMLSchemaMeta(ABCMeta):
@ -308,8 +313,8 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
if 'defaultAttributes' in root.attrib:
try:
self.default_attributes = self.resolve_qname(root.attrib['defaultAttributes'])
except XMLSchemaValueError as error:
self.parse_error(str(error), root)
except (ValueError, KeyError, RuntimeError) as err:
self.parse_error(str(err), root)
for child in root:
if child.tag == XSD_DEFAULT_OPEN_CONTENT:
@ -915,6 +920,75 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
self.imports[namespace] = schema
return schema
def version_check(self, elem):
"""
Checks if the element is compatible with the version of the validator and XSD
types/facets availability. This is always true for XSD 1.0 validators, instead
for XSD 1.1 validators checks are done against XML Schema versioning namespace.
:param elem: an Element of the schema.
:return: `True` if the schema element is compatible with the validator, \
`False` otherwise.
"""
if self.XSD_VERSION == '1.0':
return True
if VC_MIN_VERSION in elem.attrib:
vc_min_version = elem.attrib[VC_MIN_VERSION]
if not XSD_VERSION_PATTERN.match(vc_min_version):
self.parse_error("invalid attribute vc:minVersion value", elem)
elif vc_min_version > '1.1':
return False
if VC_MAX_VERSION in elem.attrib:
vc_max_version = elem.attrib[VC_MAX_VERSION]
if not XSD_VERSION_PATTERN.match(vc_max_version):
self.parse_error("invalid attribute vc:maxVersion value", elem)
elif vc_max_version <= '1.1':
return False
if VC_TYPE_AVAILABLE in elem.attrib:
for qname in elem.attrib[VC_TYPE_AVAILABLE].split():
try:
if self.resolve_qname(qname) not in self.maps.types:
return False
except (KeyError, RuntimeError):
return False
except ValueError as err:
self.parse_error(str(err), elem)
if VC_TYPE_UNAVAILABLE in elem.attrib:
for qname in elem.attrib[VC_TYPE_AVAILABLE].split():
try:
if self.resolve_qname(qname) in self.maps.types:
return False
except (KeyError, RuntimeError):
pass
except ValueError as err:
self.parse_error(str(err), elem)
if VC_FACET_AVAILABLE in elem.attrib:
for qname in elem.attrib[VC_FACET_AVAILABLE].split():
try:
if self.resolve_qname(qname) in self.maps.types:
pass
except (KeyError, RuntimeError):
pass
except ValueError as err:
self.parse_error(str(err), elem)
if VC_FACET_UNAVAILABLE in elem.attrib:
for qname in elem.attrib[VC_FACET_UNAVAILABLE].split():
try:
if self.resolve_qname(qname) in self.maps.types:
pass
except (KeyError, RuntimeError):
pass
except ValueError as err:
self.parse_error(str(err), elem)
return True
def resolve_qname(self, qname):
"""
QName resolution for a schema instance.
@ -943,7 +1017,7 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
try:
namespace = self.namespaces[prefix]
except KeyError:
raise XMLSchemaValueError("prefix %r not found in namespace map" % prefix)
raise XMLSchemaKeyError("prefix %r not found in namespace map" % prefix)
else:
namespace, local_name = self.namespaces.get('', ''), qname
@ -951,7 +1025,7 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
return local_name
elif self.meta_schema is not None and namespace != self.target_namespace and \
namespace not in {XSD_NAMESPACE, XSI_NAMESPACE} and namespace not in self.imports:
raise XMLSchemaValueError(
raise XMLSchemaNamespaceError(
"the QName {!r} is mapped to the namespace {!r}, but this namespace has "
"not an xs:import statement in the schema.".format(qname, namespace)
)
@ -1244,7 +1318,6 @@ class XMLSchema10(XMLSchemaBase):
meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.0/XMLSchema.xsd')
BASE_SCHEMAS = {
XML_NAMESPACE: XML_SCHEMA_FILE,
# HFP_NAMESPACE: HFP_SCHEMA_FILE,
XSI_NAMESPACE: XSI_SCHEMA_FILE,
XLINK_NAMESPACE: XLINK_SCHEMA_FILE,
}
@ -1306,9 +1379,9 @@ class XMLSchema11(XMLSchemaBase):
BASE_SCHEMAS = {
XSD_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XSD_1.1/list_builtins.xsd'),
XML_NAMESPACE: XML_SCHEMA_FILE,
# HFP_NAMESPACE: HFP_SCHEMA_FILE,
XSI_NAMESPACE: XSI_SCHEMA_FILE,
XLINK_NAMESPACE: XLINK_SCHEMA_FILE,
VC_NAMESPACE: VC_SCHEMA_FILE,
}
def _include_schemas(self):

View File

@ -0,0 +1,27 @@
<?xml version='1.0'?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3.org/2007/XMLSchema-versioning">
<xs:attribute name="minVersion" type="xs:decimal" />
<xs:attribute name="maxVersion" type="xs:decimal" />
<xs:attribute name="typeAvailable">
<xs:simpleType>
<xs:list itemType="xs:QName"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="typeUnavailable">
<xs:simpleType>
<xs:list itemType="xs:QName"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="facetAvailable">
<xs:simpleType>
<xs:list itemType="xs:QName"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="facetUnavailable">
<xs:simpleType>
<xs:list itemType="xs:QName"/>
</xs:simpleType>
</xs:attribute>
</xs:schema>

View File

@ -643,16 +643,16 @@ class XsdList(XsdSimpleType):
# List tag with itemType attribute that refers to a global type
try:
item_qname = self.schema.resolve_qname(elem.attrib['itemType'])
except KeyError:
self.parse_error("missing list type declaration", elem)
base_type = self.maps.types[XSD_ANY_ATOMIC_TYPE]
except ValueError as err:
self.parse_error(err, elem)
except (KeyError, ValueError, RuntimeError) as err:
if 'itemType' not in elem.attrib:
self.parse_error("missing list type declaration")
else:
self.parse_error(err)
base_type = self.maps.types[XSD_ANY_ATOMIC_TYPE]
else:
try:
base_type = self.maps.lookup_type(item_qname)
except LookupError:
except KeyError:
self.parse_error("unknown itemType %r" % elem.attrib['itemType'], elem)
base_type = self.maps.types[XSD_ANY_ATOMIC_TYPE]
@ -800,13 +800,13 @@ class XsdUnion(XsdSimpleType):
for name in elem.attrib['memberTypes'].split():
try:
type_qname = self.schema.resolve_qname(name)
except ValueError as err:
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err)
continue
try:
mt = self.maps.lookup_type(type_qname)
except LookupError:
except KeyError:
self.parse_error("unknown member type %r" % type_qname)
mt = self.maps.types[XSD_ANY_ATOMIC_TYPE]
except XMLSchemaParseError as err:
@ -995,7 +995,7 @@ class XsdAtomicRestriction(XsdAtomic):
if 'base' in elem.attrib:
try:
base_qname = self.schema.resolve_qname(elem.attrib['base'])
except ValueError as err:
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err, elem)
base_type = self.maps.type[XSD_ANY_ATOMIC_TYPE]
else:
@ -1011,7 +1011,7 @@ class XsdAtomicRestriction(XsdAtomic):
try:
base_type = self.maps.lookup_type(base_qname)
except LookupError:
except KeyError:
self.parse_error("unknown type %r." % elem.attrib['base'])
base_type = self.maps.types[XSD_ANY_ATOMIC_TYPE]
except XMLSchemaParseError as err:
@ -1039,7 +1039,7 @@ class XsdAtomicRestriction(XsdAtomic):
elif self.parent is None or self.parent.is_simple():
self.parse_error("simpleType restriction of %r is not allowed" % base_type, elem)
for child in filter(lambda x: x.tag != XSD_ANNOTATION, elem):
for child in filter(lambda x: x.tag != XSD_ANNOTATION and self.schema.version_check(x), elem):
if child.tag in {XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE}:
has_attributes = True # only if it's a complexType restriction
elif has_attributes:

View File

@ -16,12 +16,12 @@ import re
from ..compat import PY3, string_base_type, unicode_type
from ..exceptions import XMLSchemaValueError, XMLSchemaTypeError
from ..qnames import VC_MIN_VERSION, VC_MAX_VERSION, XSD_ANNOTATION, XSD_APPINFO, \
XSD_DOCUMENTATION, XML_LANG, XSD_ANY_TYPE, XSD_ID
from ..qnames import XSD_ANNOTATION, XSD_APPINFO, XSD_DOCUMENTATION, XML_LANG, XSD_ANY_TYPE, XSD_ID
from ..helpers import get_qname, local_name, qname_to_prefixed
from ..etree import etree_tostring, is_etree_element
from .exceptions import XMLSchemaParseError, XMLSchemaValidationError, XMLSchemaDecodeError, XMLSchemaEncodeError
XSD_VALIDATION_MODES = {'strict', 'lax', 'skip'}
"""
XML Schema validation modes
@ -96,26 +96,6 @@ class XsdValidator(object):
else:
return 'notKnown'
def version_check(self, elem):
"""
Checks if the element is compatible with the version of the validator. This is
always true for XSD 1.0 validators, instead for XSD 1.1 validators checks are
done against vc: minVersion and vc: maxVersion attributes. When present these
attributes must be minVersion <= 1.1 < maxVersion to let the element compatible.
:param elem: an Element of the schema.
:return: `True` if the schema element is compatible with the version of the \
validator, `False` otherwise.
"""
if self.xsd_version == '1.0':
return True
elif VC_MIN_VERSION in elem.attrib and elem.attrib[VC_MIN_VERSION] > '1.1':
return False
elif VC_MAX_VERSION in elem.attrib and elem.attrib[VC_MAX_VERSION] <= '1.1':
return False
else:
return True
def iter_components(self, xsd_classes=None):
"""
Creates an iterator for traversing all XSD components of the validator.
@ -344,7 +324,7 @@ class XsdComponent(XsdValidator):
else:
try:
self.name = self.schema.resolve_qname(ref)
except ValueError as err:
except (KeyError, ValueError, RuntimeError) as err:
self.parse_error(err)
else:
if self._parse_child_component(self.elem) is not None: