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:
parent
6e90de7b4c
commit
df5c454b24
|
@ -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
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -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__':
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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>
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue