Add XSD 1.1 support and XSD components API to documentation

This commit is contained in:
Davide Brunato 2019-08-19 13:52:30 +02:00
parent 74a45b9010
commit 9e58e99e01
22 changed files with 687 additions and 463 deletions

View File

@ -2,9 +2,9 @@
CHANGELOG
*********
`v1.0.14`_ (TDB)
================
* Added XSD 1.1 validator with class XMLSchema11 to API
`v1.0.14`_ (2019-08-19)
=======================
* Added XSD 1.1 validator with class *XMLSchema11*
* Memory usage optimization with lazy build of the XSD 1.0 and 1.1 meta-schemas
* Added facilities for the encoding of unordered and collapsed content
@ -255,3 +255,4 @@ v0.9.6 (2017-05-05)
.. _v1.0.10: https://github.com/brunato/xmlschema/compare/v1.0.9...v1.0.10
.. _v1.0.11: https://github.com/brunato/xmlschema/compare/v1.0.10...v1.0.11
.. _v1.0.13: https://github.com/brunato/xmlschema/compare/v1.0.11...v1.0.13
.. _v1.0.14: https://github.com/brunato/xmlschema/compare/v1.0.13...v1.0.14

View File

@ -26,8 +26,7 @@ Features
This library includes the following features:
* Full XSD 1.0 support
* XSD 1.1 support as prerelease
* Full XSD 1.0 and XSD 1.1 support
* Building of XML schema objects from XSD files
* Validation of XML instances against XSD schemas
* Decoding of XML data into Python data and to JSON
@ -133,11 +132,6 @@ values that match to the data types declared by the schema:
'year': '1925'}]}
Roadmap
=======
* Release 1.1 before the end of 2019: this release will drops Python 2.7 support and will
sets the XSD 1.1 validator (XMLSchema11) as the default schema class at package level.
Authors
=======
Davide Brunato and others who have contributed with code or with sample cases.

View File

@ -79,26 +79,13 @@ Schema level API
.. automethod:: iter_encode
ElementTree and XPath API
-------------------------
.. autoclass:: xmlschema.ElementPathMixin
.. autoattribute:: tag
.. autoattribute:: attrib
.. automethod:: get
.. automethod:: iter
.. automethod:: iterchildren
.. automethod:: find
.. automethod:: findall
.. automethod:: iterfind
XSD globals maps API
--------------------
XSD global maps API
-------------------
.. autoclass:: xmlschema.XsdGlobals
:members: copy, register, iter_schemas, iter_globals, clear, build
:members: copy, register, iter_schemas, iter_globals, lookup_notation, lookup_type,
lookup_attribute, lookup_attribute_group, lookup_group, lookup_element, lookup,
clear, build, unbuilt, check
.. _xml-schema-converters-api:
@ -174,6 +161,125 @@ Resource access API
.. autofunction:: xmlschema.normalize_url
XSD components API
------------------
.. note::
For XSD components only methods included in the following documentation are considered
part of the stable API, the others are considered internals that can be changed without
forewarning.
XSD elements
^^^^^^^^^^^^
.. class:: xmlschema.validators.Xsd11Element
.. autoclass:: xmlschema.validators.XsdElement
XSD attributes
^^^^^^^^^^^^^^
.. class:: xmlschema.validators.Xsd11Attribute
.. autoclass:: xmlschema.validators.XsdAttribute
XSD types
^^^^^^^^^
.. autoclass:: xmlschema.validators.XsdType
:members: is_simple, is_complex, is_atomic, is_empty, is_emptiable, has_simple_content,
has_mixed_content, is_element_only
.. class:: xmlschema.validators.Xsd11ComplexType
.. autoclass:: xmlschema.validators.XsdComplexType
.. autoclass:: xmlschema.validators.XsdSimpleType
.. class:: xmlschema.validators.XsdAtomicBuiltin
.. class:: xmlschema.validators.XsdList
.. class:: xmlschema.validators.Xsd11Union
.. class:: xmlschema.validators.XsdUnion
.. class:: xmlschema.validators.Xsd11AtomicRestriction
.. class:: xmlschema.validators.XsdAtomicRestriction
Attribute and model groups
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. autoclass:: xmlschema.validators.XsdAttributeGroup
.. class:: xmlschema.validators.Xsd11Group
.. autoclass:: xmlschema.validators.XsdGroup
Wildcards
^^^^^^^^^
.. class:: xmlschema.validators.Xsd11AnyElement
.. autoclass:: xmlschema.validators.XsdAnyElement
.. class:: xmlschema.validators.Xsd11AnyAttribute
.. autoclass:: xmlschema.validators.XsdAnyAttribute
.. autoclass:: xmlschema.validators.XsdOpenContent
.. autoclass:: xmlschema.validators.XsdDefaultOpenContent
Identity constraints
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: xmlschema.validators.XsdIdentity
.. autoclass:: xmlschema.validators.XsdSelector
.. autoclass:: xmlschema.validators.XsdFieldSelector
.. class:: xmlschema.validators.Xsd11Unique
.. class:: xmlschema.validators.XsdUnique
.. class:: xmlschema.validators.Xsd11Key
.. class:: xmlschema.validators.XsdKey
.. class:: xmlschema.validators.Xsd11Keyref
.. autoclass:: xmlschema.validators.XsdKeyref
Facets
^^^^^^
.. autoclass:: xmlschema.validators.XsdFacet
.. class:: xmlschema.validators.XsdWhiteSpaceFacet
.. class:: xmlschema.validators.XsdLengthFacet
.. class:: xmlschema.validators.XsdMinLengthFacet
.. class:: xmlschema.validators.XsdMaxLengthFacet
.. class:: xmlschema.validators.XsdMinInclusiveFacet
.. class:: xmlschema.validators.XsdMinExclusiveFacet
.. class:: xmlschema.validators.XsdMaxInclusiveFacet
.. class:: xmlschema.validators.XsdMaxExclusiveFacet
.. class:: xmlschema.validators.XsdTotalDigitsFacet
.. class:: xmlschema.validators.XsdFractionDigitsFacet
.. class:: xmlschema.validators.XsdExplicitTimezoneFacet
.. class:: xmlschema.validators.XsdAssertionFacet
.. autoclass:: xmlschema.validators.XsdEnumerationFacets
.. autoclass:: xmlschema.validators.XsdPatternFacets
Other XSD components
^^^^^^^^^^^^^^^^^^^^
.. autoclass:: xmlschema.validators.XsdAssert
.. autoclass:: xmlschema.validators.XsdAlternative
.. autoclass:: xmlschema.validators.XsdNotation
.. autoclass:: xmlschema.validators.XsdAnnotation
XSD Validation API
^^^^^^^^^^^^^^^^^^
This API is implemented for XSD schemas, elements, attributes, types, attribute
groups and model groups.
.. autoclass:: xmlschema.validators.ValidationMixin
.. automethod:: is_valid
.. automethod:: validate
.. automethod:: decode
.. automethod:: iter_decode
.. automethod:: iter_encode
.. automethod:: iter_errors
.. automethod:: encode
.. automethod:: iter_encode
ElementTree and XPath API
^^^^^^^^^^^^^^^^^^^^^^^^^
This API is implemented for XSD schemas, elements and complexType's assertions.
.. autoclass:: xmlschema.ElementPathMixin
.. autoattribute:: tag
.. autoattribute:: attrib
.. automethod:: get
.. automethod:: iter
.. automethod:: iterchildren
.. automethod:: find
.. automethod:: findall
.. automethod:: iterfind
.. _errors-and-exceptions:
Errors and exceptions

View File

@ -11,8 +11,3 @@ Support
The project is hosted on GitHub, refer to the `xmlschema's project page <https://github.com/brunato/xmlschema>`_
for source code and for an issue tracker.
Roadmap
-------
* XSD 1.1

View File

@ -553,3 +553,11 @@ From release v1.0.12 the document validation and decoding API has an optional ar
that can be changed to True for operating with a lazy :class:`XMLResource`. The lazy mode can be
useful for validating and decoding big XML data files. This is still an experimental feature that
will be refined and integrated in future versions.
XSD 1.0 and 1.1 support
-----------------------
From release v1.0.14 XSD 1.1 support has been added to the library through the class
:class:`XMLSchema11`. You have to use this class for XSD 1.1 schemas instead the default
class :class:`XMLSchema` that is still linked to XSD 1.0 validator :class:`XMLSchema10`.
From next minor release (v1.1) the default class will become :class:`XMLSchema11`.

View File

@ -20,4 +20,4 @@ from .arguments import TEST_FACTORY_OPTIONS, xsd_version_number, create_test_lin
from .factory import tests_factory
from .observers import SchemaObserver, ObservedXMLSchema10, ObservedXMLSchema11
from .schema_tests import make_schema_test_class
from .validation_tests import make_validator_test_class
from .validation_tests import make_validator_test_class

View File

@ -33,8 +33,8 @@ class TestXsdWildcards(XsdValidatorTestCase):
any1, any2, any3 = schema.groups['group1'][:]
self.assertFalse(any1.overlap(any2))
self.assertFalse(any2.overlap(any1))
self.assertFalse(any1.is_overlap(any2))
self.assertFalse(any2.is_overlap(any1))
self.assertTrue(any3.is_matching('{foo}x'))
self.assertTrue(any3.is_matching('{bar}x'))
self.assertTrue(any3.is_matching('{tns1}x'))

View File

@ -21,16 +21,19 @@ from .assertions import XsdAssert
from .notations import XsdNotation
from .identities import XsdSelector, XsdFieldSelector, XsdIdentity, XsdKeyref, XsdKey, \
XsdUnique, Xsd11Keyref, Xsd11Key, Xsd11Unique
from .facets import XsdPatternFacets, XsdEnumerationFacets
from .facets import XsdFacet, XsdWhiteSpaceFacet, XsdLengthFacet, XsdMinLengthFacet, \
XsdMaxLengthFacet, XsdMinExclusiveFacet, XsdMinInclusiveFacet, XsdMaxExclusiveFacet, \
XsdMaxInclusiveFacet, XsdFractionDigitsFacet, XsdTotalDigitsFacet, \
XsdExplicitTimezoneFacet, XsdPatternFacets, XsdEnumerationFacets, XsdAssertionFacet
from .wildcards import XsdAnyElement, Xsd11AnyElement, XsdAnyAttribute, Xsd11AnyAttribute, \
XsdOpenContent, XsdDefaultOpenContent
from .attributes import XsdAttribute, Xsd11Attribute, XsdAttributeGroup
from .simple_types import xsd_simple_type_factory, XsdSimpleType, XsdAtomic, XsdAtomicBuiltin, \
XsdAtomicRestriction, Xsd11AtomicRestriction, XsdList, XsdUnion
XsdAtomicRestriction, Xsd11AtomicRestriction, XsdList, XsdUnion, Xsd11Union
from .complex_types import XsdComplexType, Xsd11ComplexType
from .models import ModelGroup, ModelVisitor
from .groups import XsdGroup, Xsd11Group
from .elements import XsdElement, Xsd11Element
from .elements import XsdElement, Xsd11Element, XsdAlternative
from .globals_ import XsdGlobals
from .schema import XMLSchemaMeta, XMLSchemaBase, XMLSchema, XMLSchema10, XMLSchema11

View File

@ -20,15 +20,15 @@ from .xsdbase import XsdComponent
class XsdAssert(XsdComponent, ElementPathMixin):
"""
Class for XSD 'assert' constraint declaration.
Class for XSD *assert* constraint definitions.
<assert
id = ID
test = an XPath expression
xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local))
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</assert>
.. <assert
id = ID
test = an XPath expression
xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local))
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</assert>
"""
_ADMITTED_TAGS = {XSD_ASSERT}
token = None

View File

@ -31,30 +31,30 @@ from .wildcards import XsdAnyAttribute
class XsdAttribute(XsdComponent, ValidationMixin):
"""
Class for XSD 1.0 'attribute' declarations.
Class for XSD 1.0 *attribute* declarations.
<attribute
default = string
fixed = string
form = (qualified | unqualified)
id = ID
name = NCName
ref = QName
type = QName
use = (optional | prohibited | required) : optional
{any attributes with non-schema namespace ...}>
Content: (annotation?, simpleType?)
</attribute>
:ivar type: the XSD simpleType of the attribute.
.. <attribute
default = string
fixed = string
form = (qualified | unqualified)
id = ID
name = NCName
ref = QName
type = QName
use = (optional | prohibited | required) : optional
{any attributes with non-schema namespace ...}>
Content: (annotation?, simpleType?)
</attribute>
"""
_ADMITTED_TAGS = {XSD_ATTRIBUTE}
type = None
qualified = False
def __init__(self, elem, schema, parent, name=None, xsd_type=None):
if xsd_type is not None:
self.type = xsd_type
super(XsdAttribute, self).__init__(elem, schema, parent, name)
def __init__(self, elem, schema, parent):
super(XsdAttribute, self).__init__(elem, schema, parent)
self.names = (self.qualified_name,) if self.qualified else (self.qualified_name, self.local_name)
if not hasattr(self, 'type'):
raise XMLSchemaAttributeError("undefined 'type' for %r." % self)
@ -147,11 +147,11 @@ class XsdAttribute(XsdComponent, ValidationMixin):
self.parse_error(err)
xsd_type = self.maps.lookup_type(XSD_ANY_SIMPLE_TYPE)
if child and child.tag == XSD_SIMPLE_TYPE:
if child is not None and child.tag == XSD_SIMPLE_TYPE:
self.parse_error("ambiguous type definition for XSD attribute")
elif child:
elif child is not None:
self.parse_error("not allowed element in XSD attribute declaration: %r" % child[0])
elif child:
elif child is not None:
# No 'type' attribute in declaration, parse for child local simpleType
xsd_type = self.schema.BUILDERS.simple_type_factory(child, self.schema, self)
else:
@ -245,22 +245,22 @@ class XsdAttribute(XsdComponent, ValidationMixin):
class Xsd11Attribute(XsdAttribute):
"""
Class for XSD 1.1 'attribute' declarations.
Class for XSD 1.1 *attribute* declarations.
<attribute
default = string
fixed = string
form = (qualified | unqualified)
id = ID
name = NCName
ref = QName
targetNamespace = anyURI
type = QName
use = (optional | prohibited | required) : optional
inheritable = boolean
{any attributes with non-schema namespace . . .}>
Content: (annotation?, simpleType?)
</attribute>
.. <attribute
default = string
fixed = string
form = (qualified | unqualified)
id = ID
name = NCName
ref = QName
targetNamespace = anyURI
type = QName
use = (optional | prohibited | required) : optional
inheritable = boolean
{any attributes with non-schema namespace . . .}>
Content: (annotation?, simpleType?)
</attribute>
"""
inheritable = False
_target_namespace = None
@ -280,15 +280,15 @@ class Xsd11Attribute(XsdAttribute):
class XsdAttributeGroup(MutableMapping, XsdComponent, ValidationMixin):
"""
Class for XSD 'attributeGroup' definitions.
Class for XSD *attributeGroup* definitions.
<attributeGroup
id = ID
name = NCName
ref = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?))
</attributeGroup>
.. <attributeGroup
id = ID
name = NCName
ref = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?))
</attributeGroup>
"""
redefine = None
_ADMITTED_TAGS = {
@ -296,11 +296,11 @@ class XsdAttributeGroup(MutableMapping, XsdComponent, ValidationMixin):
XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE
}
def __init__(self, elem, schema, parent, name=None, derivation=None, base_attributes=None):
def __init__(self, elem, schema, parent, derivation=None, base_attributes=None):
self.derivation = derivation
self._attribute_group = ordered_dict_class()
self.base_attributes = base_attributes
XsdComponent.__init__(self, elem, schema, parent, name)
XsdComponent.__init__(self, elem, schema, parent)
def __repr__(self):
if self.ref is not None:

View File

@ -33,19 +33,23 @@ SEQUENCE_ELEMENT = etree_element(XSD_SEQUENCE)
class XsdComplexType(XsdType, ValidationMixin):
"""
Class for XSD 1.0 'complexType' definitions.
Class for XSD 1.0 *complexType* definitions.
<complexType
abstract = boolean : false
block = (#all | List of (extension | restriction))
final = (#all | List of (extension | restriction))
id = ID
mixed = boolean : false
name = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleContent | complexContent |
((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))))
</complexType>
:var attributes: the attribute group related with the type.
:var content_type: the content type, that can be a model group or a simple type.
:var mixed: if `True` the complex type has mixed content.
.. <complexType
abstract = boolean : false
block = (#all | List of (extension | restriction))
final = (#all | List of (extension | restriction))
id = ID
mixed = boolean : false
name = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleContent | complexContent |
((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))))
</complexType>
"""
abstract = False
mixed = False
@ -645,20 +649,20 @@ class XsdComplexType(XsdType, ValidationMixin):
class Xsd11ComplexType(XsdComplexType):
"""
Class for XSD 1.1 'complexType' definitions.
Class for XSD 1.1 *complexType* definitions.
<complexType
abstract = boolean : false
block = (#all | List of (extension | restriction))
final = (#all | List of (extension | restriction))
id = ID
mixed = boolean
name = NCName
defaultAttributesApply = boolean : true
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleContent | complexContent | (openContent?,
(group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?), assert*)))
</complexType>
.. <complexType
abstract = boolean : false
block = (#all | List of (extension | restriction))
final = (#all | List of (extension | restriction))
id = ID
mixed = boolean
name = NCName
defaultAttributesApply = boolean : true
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleContent | complexContent | (openContent?,
(group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?), assert*)))
</complexType>
"""
default_attributes_apply = True

View File

@ -39,29 +39,33 @@ XSD_ATTRIBUTE_GROUP_ELEMENT = etree_element(XSD_ATTRIBUTE_GROUP)
class XsdElement(XsdComponent, ValidationMixin, ParticleMixin, ElementPathMixin):
"""
Class for XSD 1.0 'element' declarations.
Class for XSD 1.0 *element* declarations.
<element
abstract = boolean : false
block = (#all | List of (extension | restriction | substitution))
default = string
final = (#all | List of (extension | restriction))
fixed = string
form = (qualified | unqualified)
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
name = NCName
nillable = boolean : false
ref = QName
substitutionGroup = QName
type = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*))
</element>
:ivar type: the XSD simpleType or complexType of the element.
:ivar attributes: the group of the attributes associated with the element.
.. <element
abstract = boolean : false
block = (#all | List of (extension | restriction | substitution))
default = string
final = (#all | List of (extension | restriction))
fixed = string
form = (qualified | unqualified)
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
name = NCName
nillable = boolean : false
ref = QName
substitutionGroup = QName
type = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*))
</element>
"""
type = None
qualified = False
attributes = None
_ADMITTED_TAGS = {XSD_ELEMENT}
_abstract = False
@ -71,8 +75,8 @@ class XsdElement(XsdComponent, ValidationMixin, ParticleMixin, ElementPathMixin)
_nillable = False
_substitution_group = None
def __init__(self, elem, schema, parent, name=None):
super(XsdElement, self).__init__(elem, schema, parent, name)
def __init__(self, elem, schema, parent):
super(XsdElement, self).__init__(elem, schema, parent)
self.names = (self.qualified_name,) if self.qualified else (self.qualified_name, self.local_name)
if self.type is None:
raise XMLSchemaAttributeError("undefined 'type' attribute for %r." % self)
@ -729,7 +733,7 @@ class XsdElement(XsdComponent, ValidationMixin, ParticleMixin, ElementPathMixin)
return False
return True
def overlap(self, other):
def is_overlap(self, other):
if isinstance(other, XsdElement):
if self.name == other.name:
return True
@ -743,30 +747,46 @@ class XsdElement(XsdComponent, ValidationMixin, ParticleMixin, ElementPathMixin)
return True
return False
def is_consistent(self, other):
"""
Element Declarations Consistent check between two element particles.
Ref: https://www.w3.org/TR/xmlschema-1/#cos-element-consistent
:returns: `True` if there is no inconsistency between the particles, `False` otherwise,
"""
if isinstance(other, XsdAnyElement):
xsd_element = other.matched_element(self.name, self.default_namespace)
return xsd_element is None or self.is_consistent(xsd_element)
elif self.name != other.name:
return True
else:
return self.type is other.type
class Xsd11Element(XsdElement):
"""
Class for XSD 1.1 'element' declarations.
Class for XSD 1.1 *element* declarations.
<element
abstract = boolean : false
block = (#all | List of (extension | restriction | substitution))
default = string
final = (#all | List of (extension | restriction))
fixed = string
form = (qualified | unqualified)
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
name = NCName
nillable = boolean : false
ref = QName
substitutionGroup = List of QName
targetNamespace = anyURI
type = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((simpleType | complexType)?, alternative*, (unique | key | keyref)*))
</element>
.. <element
abstract = boolean : false
block = (#all | List of (extension | restriction | substitution))
default = string
final = (#all | List of (extension | restriction))
fixed = string
form = (qualified | unqualified)
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
name = NCName
nillable = boolean : false
ref = QName
substitutionGroup = List of QName
targetNamespace = anyURI
type = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((simpleType | complexType)?, alternative*, (unique | key | keyref)*))
</element>
"""
alternatives = ()
_target_namespace = None
@ -828,7 +848,7 @@ class Xsd11Element(XsdElement):
return alt.type
return self.type
def overlap(self, other):
def is_overlap(self, other):
if isinstance(other, XsdElement):
if self.name == other.name:
return True
@ -836,26 +856,52 @@ class Xsd11Element(XsdElement):
return True
return False
def is_consistent(self, other):
if isinstance(other, XsdAnyElement):
xsd_element = other.matched_element(self.name, self.default_namespace)
return xsd_element is None or self.is_consistent(xsd_element)
elif self.name != other.name:
return True
elif self.type is not other.type or len(self.alternatives) != len(other.alternatives):
return False
elif not self.alternatives:
return True
elif not all(any(a == x) for x in other.alternatives for a in self.alternatives):
return False
else:
return all(any(a == x) for x in self.alternatives for a in other.alternatives)
class XsdAlternative(XsdComponent):
"""
<alternative
id = ID
test = an XPath expression
type = QName
xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local))
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleType | complexType)?)
</alternative>
XSD 1.1 type *alternative* definitions.
.. <alternative
id = ID
test = an XPath expression
type = QName
xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local))
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleType | complexType)?)
</alternative>
"""
type = None
path = None
token = None
_ADMITTED_TAGS = {XSD_ALTERNATIVE}
def __init__(self, elem, schema, parent):
super(XsdAlternative, self).__init__(elem, schema, parent)
def __repr__(self):
return '%s(type=%r, test=%r)' % (self.__class__.__name__, self.elem.get('type'), self.elem.get('test'))
def __eq__(self, other):
return self.path == other.path and self.type is other.type
def __ne__(self, other):
return self.path != other.path or self.type is not other.type
def _parse(self):
XsdComponent._parse(self)
attrib = self.elem.attrib

View File

@ -90,15 +90,15 @@ class XsdFacet(XsdComponent):
class XsdWhiteSpaceFacet(XsdFacet):
"""
XSD whiteSpace facet.
XSD *whiteSpace* facet.
<whiteSpace
fixed = boolean : false
id = ID
value = (collapse | preserve | replace)
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</whiteSpace>
.. <whiteSpace
fixed = boolean : false
id = ID
value = (collapse | preserve | replace)
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</whiteSpace>
"""
_ADMITTED_TAGS = XSD_WHITE_SPACE,
@ -126,15 +126,15 @@ class XsdWhiteSpaceFacet(XsdFacet):
class XsdLengthFacet(XsdFacet):
"""
XSD length facet.
XSD *length* facet.
<length
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</length>
.. <length
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</length>
"""
_ADMITTED_TAGS = XSD_LENGTH,
@ -169,15 +169,15 @@ class XsdLengthFacet(XsdFacet):
class XsdMinLengthFacet(XsdFacet):
"""
XSD minLength facet.
XSD *minLength* facet.
<minLength
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minLength>
.. <minLength
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minLength>
"""
_ADMITTED_TAGS = XSD_MIN_LENGTH,
@ -212,15 +212,15 @@ class XsdMinLengthFacet(XsdFacet):
class XsdMaxLengthFacet(XsdFacet):
"""
XSD maxLength facet.
XSD *maxLength* facet.
<maxLength
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxLength>
.. <maxLength
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxLength>
"""
_ADMITTED_TAGS = XSD_MAX_LENGTH,
@ -255,15 +255,15 @@ class XsdMaxLengthFacet(XsdFacet):
class XsdMinInclusiveFacet(XsdFacet):
"""
XSD minInclusive facet.
XSD *minInclusive* facet.
<minInclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minInclusive>
.. <minInclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minInclusive>
"""
_ADMITTED_TAGS = XSD_MIN_INCLUSIVE,
@ -293,15 +293,15 @@ class XsdMinInclusiveFacet(XsdFacet):
class XsdMinExclusiveFacet(XsdFacet):
"""
XSD minExclusive facet.
XSD *minExclusive* facet.
<minExclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minExclusive>
.. <minExclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minExclusive>
"""
_ADMITTED_TAGS = XSD_MIN_EXCLUSIVE,
@ -331,15 +331,15 @@ class XsdMinExclusiveFacet(XsdFacet):
class XsdMaxInclusiveFacet(XsdFacet):
"""
XSD maxInclusive facet.
XSD *maxInclusive* facet.
<maxInclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxInclusive>
.. <maxInclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxInclusive>
"""
_ADMITTED_TAGS = XSD_MAX_INCLUSIVE,
@ -369,15 +369,15 @@ class XsdMaxInclusiveFacet(XsdFacet):
class XsdMaxExclusiveFacet(XsdFacet):
"""
XSD maxExclusive facet.
XSD *maxExclusive* facet.
<maxExclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxExclusive>
.. <maxExclusive
fixed = boolean : false
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxExclusive>
"""
_ADMITTED_TAGS = XSD_MAX_EXCLUSIVE,
@ -407,15 +407,15 @@ class XsdMaxExclusiveFacet(XsdFacet):
class XsdTotalDigitsFacet(XsdFacet):
"""
XSD totalDigits facet.
XSD *totalDigits* facet.
<totalDigits
fixed = boolean : false
id = ID
value = positiveInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</totalDigits>
.. <totalDigits
fixed = boolean : false
id = ID
value = positiveInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</totalDigits>
"""
_ADMITTED_TAGS = XSD_TOTAL_DIGITS,
@ -432,15 +432,15 @@ class XsdTotalDigitsFacet(XsdFacet):
class XsdFractionDigitsFacet(XsdFacet):
"""
XSD fractionDigits facet.
XSD *fractionDigits* facet.
<fractionDigits
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</fractionDigits>
.. <fractionDigits
fixed = boolean : false
id = ID
value = nonNegativeInteger
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</fractionDigits>
"""
_ADMITTED_TAGS = XSD_FRACTION_DIGITS,
@ -464,15 +464,15 @@ class XsdFractionDigitsFacet(XsdFacet):
class XsdExplicitTimezoneFacet(XsdFacet):
"""
XSD 1.1 explicitTimezone facet.
XSD 1.1 *explicitTimezone* facet.
<explicitTimezone
fixed = boolean : false
id = ID
value = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</explicitTimezone>
.. <explicitTimezone
fixed = boolean : false
id = ID
value = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</explicitTimezone>
"""
_ADMITTED_TAGS = XSD_EXPLICIT_TIMEZONE,
@ -496,14 +496,14 @@ class XsdExplicitTimezoneFacet(XsdFacet):
class XsdEnumerationFacets(MutableSequence, XsdFacet):
"""
Sequence of XSD enumeration facets. Values are validates if match any of enumeration values.
Sequence of XSD *enumeration* facets. Values are validates if match any of enumeration values.
<enumeration
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</enumeration>
.. <enumeration
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</enumeration>
"""
_ADMITTED_TAGS = {XSD_ENUMERATION}
@ -570,14 +570,14 @@ class XsdEnumerationFacets(MutableSequence, XsdFacet):
class XsdPatternFacets(MutableSequence, XsdFacet):
"""
Sequence of XSD pattern facets. Values are validates if match any of patterns.
Sequence of XSD *pattern* facets. Values are validates if match any of patterns.
<pattern
id = ID
value = string
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</pattern>
.. <pattern
id = ID
value = string
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</pattern>
"""
_ADMITTED_TAGS = {XSD_PATTERN}
@ -637,15 +637,15 @@ class XsdPatternFacets(MutableSequence, XsdFacet):
class XsdAssertionFacet(XsdFacet):
"""
XSD 1.1 assertion facet for simpleType definitions.
XSD 1.1 *assertion* facet for simpleType definitions.
<assertion
id = ID
test = an XPath expression
xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local))
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</assertion>
.. <assertion
id = ID
test = an XPath expression
xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local))
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</assertion>
"""
_ADMITTED_TAGS = {XSD_ASSERTION}

View File

@ -254,6 +254,17 @@ class XsdGlobals(XsdValidator):
return lookup_element(self.elements, qname, self.validator.BUILDERS_MAP)
def lookup(self, tag, qname):
"""
General lookup method for XSD global components.
:param tag: the expanded QName of the XSD the global declaration/definition \
(eg. '{http://www.w3.org/2001/XMLSchema}element'), that is used to select \
the global map for lookup.
:param qname: the expanded QName of the component to be looked-up.
:returns: an XSD global component.
:raises: an XMLSchemaValueError if the *tag* argument is not appropriate for a global \
component, an XMLSchemaKeyError if the *qname* argument is not found in the global map.
"""
if tag in (XSD_SIMPLE_TYPE, XSD_COMPLEX_TYPE):
return self.lookup_type(qname)
elif tag == XSD_ELEMENT:
@ -538,3 +549,4 @@ class XsdGlobals(XsdValidator):
if validation == 'strict':
raise
xsd_type.errors.append(err)

View File

@ -38,41 +38,41 @@ ANY_ELEMENT = etree_element(
class XsdGroup(XsdComponent, ModelGroup, ValidationMixin):
"""
A class for XSD 1.0 model group definitions.
Class for XSD 1.0 *model group* definitions.
<group
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
name = NCName
ref = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (all | choice | sequence)?)
</group>
.. <group
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
name = NCName
ref = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (all | choice | sequence)?)
</group>
<all
id = ID
maxOccurs = 1 : 1
minOccurs = (0 | 1) : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, element*)
</all>
.. <all
id = ID
maxOccurs = 1 : 1
minOccurs = (0 | 1) : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, element*)
</all>
<choice
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | group | choice | sequence | any)*)
</choice>
.. <choice
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | group | choice | sequence | any)*)
</choice>
<sequence
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | group | choice | sequence | any)*)
</sequence>
.. <sequence
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | group | choice | sequence | any)*)
</sequence>
"""
mixed = False
model = None
@ -84,11 +84,11 @@ class XsdGroup(XsdComponent, ModelGroup, ValidationMixin):
XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_RESTRICTION, XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE
}
def __init__(self, elem, schema, parent, name=None):
def __init__(self, elem, schema, parent):
self._group = []
if parent is not None and parent.mixed:
self.mixed = parent.mixed
super(XsdGroup, self).__init__(elem, schema, parent, name)
super(XsdGroup, self).__init__(elem, schema, parent)
def __repr__(self):
if self.name is None:
@ -724,16 +724,16 @@ class XsdGroup(XsdComponent, ModelGroup, ValidationMixin):
class Xsd11Group(XsdGroup):
"""
A class for XSD 1.1 model group definitions. The XSD 1.1 model groups differ
from XSD 1.0 groups for the 'all' model, that can contains also other groups.
Class for XSD 1.1 *model group* definitions.
<all
id = ID
maxOccurs = (0 | 1) : 1
minOccurs = (0 | 1) : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | any | group)*)
</all>
.. The XSD 1.1 model groups differ from XSD 1.0 groups for the 'all' model, that can contains also other groups.
.. <all
id = ID
maxOccurs = (0 | 1) : 1
minOccurs = (0 | 1) : 1
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | any | group)*)
</all>
"""
def _parse_content_model(self, elem, content_model):
self.model = local_name(content_model.tag)

View File

@ -44,6 +44,7 @@ XsdIdentityXPathParser.build_tokenizer()
class XsdSelector(XsdComponent):
"""Class for defining an XPath selector for an XSD identity constraint."""
_ADMITTED_TAGS = {XSD_SELECTOR}
pattern = re.compile(get_python_regex(
r"(\.//)?(((child::)?((\i\c*:)?(\i\c*|\*)))|\.)(/(((child::)?((\i\c*:)?(\i\c*|\*)))|\.))*(\|"
@ -86,6 +87,7 @@ class XsdSelector(XsdComponent):
class XsdFieldSelector(XsdSelector):
"""Class for defining an XPath field selector for an XSD identity constraint."""
_ADMITTED_TAGS = {XSD_FIELD}
pattern = re.compile(get_python_regex(
r"(\.//)?((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)/)*((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)|"
@ -95,9 +97,18 @@ class XsdFieldSelector(XsdSelector):
class XsdIdentity(XsdComponent):
"""
Common class for XSD identity constraints.
:ivar selector: the XPath selector of the identity constraint.
:ivar fields: a list containing the XPath field selectors of the identity constraint.
"""
selector = None
fields = ()
def __init__(self, elem, schema, parent):
super(XsdIdentity, self).__init__(elem, schema, parent)
def _parse(self):
super(XsdIdentity, self)._parse()
elem = self.elem

View File

@ -176,8 +176,9 @@ class ModelGroup(MutableSequence, ParticleMixin):
def check_model(self):
"""
Checks if the model group is deterministic. Types matching of same elements and Unique Particle
Attribution Constraint are checked. Raises an `XMLSchemaModelError` at first violated constraint.
Checks if the model group is deterministic. Element Declarations Consistent and
Unique Particle Attribution constraints are checked.
:raises: an `XMLSchemaModelError` at first violated constraint.
"""
def safe_iter_path(group, depth):
if depth > MAX_MODEL_DEPTH:
@ -195,11 +196,14 @@ class ModelGroup(MutableSequence, ParticleMixin):
current_path = [self]
for e in safe_iter_path(self, 0):
for pe, previous_path in paths.values():
if pe.name == e.name and pe.name is not None and pe.type is not e.type:
raise XMLSchemaModelError(
self, "The model has elements with the same name %r but a different type" % e.name
)
elif not pe.overlap(e):
# EDC check
if not e.is_consistent(pe):
msg = "Element Declarations Consistent violation between %r and %r: " \
"match the same name but with different types" % (e, pe)
raise XMLSchemaModelError(self, msg)
# UPA check
if not pe.is_overlap(e):
continue
elif pe is not e and pe.parent is e.parent:
if pe.parent.model in {'all', 'choice'}:

View File

@ -19,31 +19,26 @@ from .xsdbase import XsdComponent
class XsdNotation(XsdComponent):
"""
Class for XSD 'notation' declarations.
Class for XSD *notation* declarations.
<notation
id = ID
name = NCName
public = token
system = anyURI
{any attributes with non-schema namespace}...>
Content: (annotation?)
</notation>
.. <notation
id = ID
name = NCName
public = token
system = anyURI
{any attributes with non-schema namespace}...>
Content: (annotation?)
</notation>
"""
_ADMITTED_TAGS = {XSD_NOTATION}
def __init__(self, elem, schema, parent):
if parent is not None:
raise XMLSchemaValueError("'parent' attribute is not None but %r must be global!" % self)
super(XsdNotation, self).__init__(elem, schema, parent)
@property
def built(self):
return True
def _parse(self):
super(XsdNotation, self)._parse()
if not self.is_global:
if self.parent is not None:
self.parse_error("a notation declaration must be global", self.elem)
try:
self.name = get_qname(self.target_namespace, self.elem.attrib['name'])

View File

@ -605,15 +605,15 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
"""Creates a new schema instance of the same class of the caller."""
return cls(*args, **kwargs)
def create_any_content_group(self, parent, name=None):
def create_any_content_group(self, parent):
"""Creates a model group related to schema instance that accepts any content."""
group = self.BUILDERS.group_class(SEQUENCE_ELEMENT, self, parent, name)
group = self.BUILDERS.group_class(SEQUENCE_ELEMENT, self, parent)
group.append(self.BUILDERS.any_element_class(ANY_ELEMENT, self, group))
return group
def create_any_attribute_group(self, parent, name=None):
def create_any_attribute_group(self, parent):
"""Creates an attribute group related to schema instance that accepts any attribute."""
attribute_group = self.BUILDERS.attribute_group_class(ATTRIBUTE_GROUP_ELEMENT, self, parent, name)
attribute_group = self.BUILDERS.attribute_group_class(ATTRIBUTE_GROUP_ELEMENT, self, parent)
attribute_group[None] = self.BUILDERS.any_attribute_class(ANY_ATTRIBUTE_ELEMENT, self, attribute_group)
return attribute_group
@ -1108,7 +1108,8 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
yield self.validation_error('lax', "%r is not an element of the schema" % source.root, source.root)
for result in xsd_element.iter_decode(source.root, source=source, namespaces=namespaces,
use_defaults=use_defaults, id_map=id_map, no_depth=True):
use_defaults=use_defaults, id_map=id_map,
no_depth=True, drop_results=True):
if isinstance(result, XMLSchemaValidationError):
yield result
else:
@ -1124,7 +1125,8 @@ class XMLSchemaBase(XsdValidator, ValidationMixin, ElementPathMixin):
yield self.validation_error('lax', "%r is not an element of the schema" % elem, elem)
for result in xsd_element.iter_decode(elem, source=source, namespaces=namespaces,
use_defaults=use_defaults, id_map=id_map):
use_defaults=use_defaults, id_map=id_map,
drop_results=True):
if isinstance(result, XMLSchemaValidationError):
yield result
else:

View File

@ -90,13 +90,13 @@ class XsdSimpleType(XsdType, ValidationMixin):
Base class for simpleTypes definitions. Generally used only for
instances of xs:anySimpleType.
<simpleType
final = (#all | List of (list | union | restriction | extension))
id = ID
name = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (restriction | list | union))
</simpleType>
.. <simpleType
final = (#all | List of (list | union | restriction | extension))
id = ID
name = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (restriction | list | union))
</simpleType>
"""
_special_types = {XSD_ANY_TYPE, XSD_ANY_SIMPLE_TYPE}
_ADMITTED_TAGS = {XSD_SIMPLE_TYPE}
@ -599,12 +599,12 @@ class XsdList(XsdSimpleType):
Class for 'list' definitions. A list definition has an item_type attribute
that refers to an atomic or union simpleType definition.
<list
id = ID
itemType = QName
{any attributes with non-schema namespace ...}>
Content: (annotation?, simpleType?)
</list>
.. <list
id = ID
itemType = QName
{any attributes with non-schema namespace ...}>
Content: (annotation?, simpleType?)
</list>
"""
_ADMITTED_TAGS = {XSD_LIST}
_white_space_elem = etree_element(XSD_WHITE_SPACE, attrib={'value': 'collapse', 'fixed': 'true'})
@ -759,12 +759,12 @@ class XsdUnion(XsdSimpleType):
Class for 'union' definitions. A union definition has a member_types
attribute that refers to a 'simpleType' definition.
<union
id = ID
memberTypes = List of QName
{any attributes with non-schema namespace ...}>
Content: (annotation?, simpleType*)
</union>
.. <union
id = ID
memberTypes = List of QName
{any attributes with non-schema namespace ...}>
Content: (annotation?, simpleType*)
</union>
"""
_ADMITTED_TYPES = XsdSimpleType
_ADMITTED_TAGS = {XSD_UNION}
@ -968,14 +968,14 @@ class XsdAtomicRestriction(XsdAtomic):
"""
Class for XSD 1.0 atomic simpleType and complexType's simpleContent restrictions.
<restriction
base = QName
id = ID
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive |
maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength |
enumeration | whiteSpace | pattern)*))
</restriction>
.. <restriction
base = QName
id = ID
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive |
maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength |
enumeration | whiteSpace | pattern)*))
</restriction>
"""
FACETS_BUILDERS = XSD_10_FACETS_BUILDERS
derivation = 'restriction'
@ -1208,15 +1208,15 @@ class Xsd11AtomicRestriction(XsdAtomicRestriction):
"""
Class for XSD 1.1 atomic simpleType and complexType's simpleContent restrictions.
<restriction
base = QName
id = ID
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive |
maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength |
enumeration | whiteSpace | pattern | assertion | explicitTimezone |
{any with namespace: ##other})*))
</restriction>
.. <restriction
base = QName
id = ID
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive |
maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength |
enumeration | whiteSpace | pattern | assertion | explicitTimezone |
{any with namespace: ##other})*))
</restriction>
"""
FACETS_BUILDERS = XSD_11_FACETS_BUILDERS
_CONTENT_TAIL_TAGS = {XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE, XSD_ASSERT}

View File

@ -178,8 +178,13 @@ class XsdWildcard(XsdComponent, ValidationMixin):
return False
if self.not_qname:
if other.not_namespace and \
all(get_namespace(x) in other.not_namespace for x in self.not_qname):
if '##defined' in other.not_qname and '##defined' not in self.not_qname:
return False
elif '##definedSibling' in other.not_qname and '##definedSibling' not in self.not_qname:
return False
elif other.not_namespace and \
all(get_namespace(x) in other.not_namespace
for x in self.not_qname if not x.startswith('##')):
return True
elif '##any' in other.namespace:
return True
@ -205,7 +210,7 @@ class XsdWildcard(XsdComponent, ValidationMixin):
if '##any' in self.namespace:
return False
elif '##other' in self.namespace:
return set(['', other.target_namespace]) == set(other.not_namespace)
return {'', other.target_namespace} == set(other.not_namespace)
else:
return any(ns not in other.not_namespace for ns in self.namespace)
@ -276,17 +281,17 @@ class XsdWildcard(XsdComponent, ValidationMixin):
class XsdAnyElement(XsdWildcard, ParticleMixin, ElementPathMixin):
"""
Class for XSD 1.0 'any' wildcards.
Class for XSD 1.0 *any* wildcards.
<any
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) : ##any
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</any>
.. <any
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) : ##any
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</any>
"""
_ADMITTED_TAGS = {XSD_ANY}
@ -341,7 +346,10 @@ class XsdAnyElement(XsdWildcard, ParticleMixin, ElementPathMixin):
try:
xsd_element = self.maps.lookup_element(elem.tag)
except LookupError:
if self.process_contents == 'strict' and validation != 'skip':
if kwargs.get('drop_results'):
# Validation-only mode: use anyType for decode a complex element.
yield self.any_type.decode(elem) if len(elem) > 0 else elem.text
elif self.process_contents == 'strict' and validation != 'skip':
reason = "element %r not found." % elem.tag
yield self.validation_error(validation, reason, elem, **kwargs)
else:
@ -372,9 +380,9 @@ class XsdAnyElement(XsdWildcard, ParticleMixin, ElementPathMixin):
reason = "element %r not allowed here." % name
yield self.validation_error(validation, reason, value, **kwargs)
def overlap(self, other):
def is_overlap(self, other):
if not isinstance(other, XsdAnyElement):
return other.overlap(self)
return other.is_overlap(self)
elif self.not_namespace:
if other.not_namespace:
return True
@ -402,18 +410,24 @@ class XsdAnyElement(XsdWildcard, ParticleMixin, ElementPathMixin):
else:
return any(ns in self.namespace for ns in other.namespace)
def is_consistent(self, other):
if isinstance(other, XsdAnyElement):
return True
xsd_element = self.matched_element(other.name, other.default_namespace)
return xsd_element is None or other.is_consistent(xsd_element)
class XsdAnyAttribute(XsdWildcard):
"""
Class for XSD 1.0 'anyAttribute' wildcards.
Class for XSD 1.0 *anyAttribute* wildcards.
<anyAttribute
id = ID
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</anyAttribute>
.. <anyAttribute
id = ID
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</anyAttribute>
"""
_ADMITTED_TAGS = {XSD_ANY_ATTRIBUTE}
@ -428,7 +442,10 @@ class XsdAnyAttribute(XsdWildcard):
try:
xsd_attribute = self.maps.lookup_attribute(name)
except LookupError:
if self.process_contents == 'strict' and validation != 'skip':
if kwargs.get('drop_results'):
# Validation-only mode: returns the value if a decoder is not found.
yield value
elif self.process_contents == 'strict' and validation != 'skip':
reason = "attribute %r not found." % name
yield self.validation_error(validation, reason, attribute, **kwargs)
else:
@ -462,19 +479,19 @@ class XsdAnyAttribute(XsdWildcard):
class Xsd11AnyElement(XsdAnyElement):
"""
Class for XSD 1.1 'any' declarations.
Class for XSD 1.1 *any* declarations.
<any
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )
notNamespace = List of (anyURI | (##targetNamespace | ##local))
notQName = List of (QName | (##defined | ##definedSibling))
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</any>
.. <any
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
minOccurs = nonNegativeInteger : 1
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )
notNamespace = List of (anyURI | (##targetNamespace | ##local))
notQName = List of (QName | (##defined | ##definedSibling))
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</any>
"""
def _parse(self):
super(Xsd11AnyElement, self)._parse()
@ -502,17 +519,17 @@ class Xsd11AnyElement(XsdAnyElement):
class Xsd11AnyAttribute(XsdAnyAttribute):
"""
Class for XSD 1.1 'anyAttribute' declarations.
Class for XSD 1.1 *anyAttribute* declarations.
<anyAttribute
id = ID
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )
notNamespace = List of (anyURI | (##targetNamespace | ##local))
notQName = List of (QName | ##defined)
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</anyAttribute>
.. <anyAttribute
id = ID
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) )
notNamespace = List of (anyURI | (##targetNamespace | ##local))
notQName = List of (QName | ##defined)
processContents = (lax | skip | strict) : strict
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</anyAttribute>
"""
def _parse(self):
super(Xsd11AnyAttribute, self)._parse()
@ -537,19 +554,22 @@ class Xsd11AnyAttribute(XsdAnyAttribute):
class XsdOpenContent(XsdComponent):
"""
Class for XSD 1.1 'openContent' model definitions.
Class for XSD 1.1 *openContent* model definitions.
<openContent
id = ID
mode = (none | interleave | suffix) : interleave
{any attributes with non-schema namespace . . .}>
Content: (annotation?), (any?)
</openContent>
.. <openContent
id = ID
mode = (none | interleave | suffix) : interleave
{any attributes with non-schema namespace . . .}>
Content: (annotation?), (any?)
</openContent>
"""
_ADMITTED_TAGS = {XSD_OPEN_CONTENT}
mode = 'interleave'
any_element = None
def __init__(self, elem, schema, parent):
super(XsdOpenContent, self).__init__(elem, schema, parent)
def __repr__(self):
return '%s(mode=%r)' % (self.__class__.__name__, self.mode)
@ -590,19 +610,22 @@ class XsdOpenContent(XsdComponent):
class XsdDefaultOpenContent(XsdOpenContent):
"""
Class for XSD 1.1 'defaultOpenContent' model definitions.
Class for XSD 1.1 *defaultOpenContent* model definitions.
<defaultOpenContent
appliesToEmpty = boolean : false
id = ID
mode = (interleave | suffix) : interleave
{any attributes with non-schema namespace . . .}>
Content: (annotation?, any)
</defaultOpenContent>
.. <defaultOpenContent
appliesToEmpty = boolean : false
id = ID
mode = (interleave | suffix) : interleave
{any attributes with non-schema namespace . . .}>
Content: (annotation?, any)
</defaultOpenContent>
"""
_ADMITTED_TAGS = {XSD_DEFAULT_OPEN_CONTENT}
applies_to_empty = False
def __init__(self, elem, schema):
super(XsdOpenContent, self).__init__(elem, schema)
def _parse(self):
super(XsdDefaultOpenContent, self)._parse()
if self.parent is not None:

View File

@ -512,26 +512,29 @@ class XsdComponent(XsdValidator):
class XsdAnnotation(XsdComponent):
"""
Class for XSD 'annotation' definitions.
Class for XSD *annotation* definitions.
<annotation
id = ID
{any attributes with non-schema namespace . . .}>
Content: (appinfo | documentation)*
</annotation>
:var appinfo: a list containing the xs:appinfo children.
:var documentation: a list containing the xs:documentation children.
<appinfo
source = anyURI
{any attributes with non-schema namespace . . .}>
Content: ({any})*
</appinfo>
.. <annotation
id = ID
{any attributes with non-schema namespace . . .}>
Content: (appinfo | documentation)*
</annotation>
<documentation
source = anyURI
xml:lang = language
{any attributes with non-schema namespace . . .}>
Content: ({any})*
</documentation>
.. <appinfo
source = anyURI
{any attributes with non-schema namespace . . .}>
Content: ({any})*
</appinfo>
.. <documentation
source = anyURI
xml:lang = language
{any attributes with non-schema namespace . . .}>
Content: ({any})*
</documentation>
"""
_ADMITTED_TAGS = {XSD_ANNOTATION}
@ -557,6 +560,8 @@ class XsdAnnotation(XsdComponent):
class XsdType(XsdComponent):
"""Common base class for XSD types."""
abstract = False
base_type = None
derivation = None
@ -573,29 +578,44 @@ class XsdType(XsdComponent):
@staticmethod
def is_simple():
"""Returns `True` if the instance is a simpleType, `False` otherwise."""
raise NotImplementedError
@staticmethod
def is_complex():
"""Returns `True` if the instance is a complexType, `False` otherwise."""
raise NotImplementedError
@staticmethod
def is_atomic():
"""Returns `True` if the instance is an atomic simpleType, `False` otherwise."""
return None
def is_empty(self):
"""Returns `True` if the instance has an empty value or content, `False` otherwise."""
raise NotImplementedError
def is_emptiable(self):
"""Returns `True` if the instance has an emptiable value or content, `False` otherwise."""
raise NotImplementedError
def has_simple_content(self):
"""
Returns `True` if the instance is a simpleType or a complexType with simple
content, `False` otherwise.
"""
raise NotImplementedError
def has_mixed_content(self):
"""
Returns `True` if the instance is a complexType with mixed content, `False` otherwise.
"""
raise NotImplementedError
def is_element_only(self):
"""
Returns `True` if the instance is a complexType with element-only content, `False` otherwise.
"""
raise NotImplementedError
@property