2017-05-23 16:45:10 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
2019-01-20 16:53:23 +01:00
|
|
|
# Copyright (c), 2016-2019, SISSA (International School for Advanced Studies).
|
2017-05-23 16:45:10 +02:00
|
|
|
# All rights reserved.
|
|
|
|
# This file is distributed under the terms of the MIT License.
|
|
|
|
# See the file 'LICENSE' in the root directory of the present
|
|
|
|
# distribution, or http://opensource.org/licenses/MIT.
|
|
|
|
#
|
|
|
|
# @author Davide Brunato <brunato@sissa.it>
|
|
|
|
#
|
|
|
|
"""
|
2019-10-07 15:31:18 +02:00
|
|
|
This module contains qualified names constants and helpers.
|
2017-05-23 16:45:10 +02:00
|
|
|
"""
|
2018-09-15 16:50:33 +02:00
|
|
|
from __future__ import unicode_literals
|
2019-10-07 15:31:18 +02:00
|
|
|
from .exceptions import XMLSchemaTypeError, XMLSchemaValueError
|
|
|
|
from .namespaces import get_namespace
|
2017-05-23 16:45:10 +02:00
|
|
|
|
2019-07-30 21:06:54 +02:00
|
|
|
VC_TEMPLATE = '{http://www.w3.org/2007/XMLSchema-versioning}%s'
|
|
|
|
XML_TEMPLATE = '{http://www.w3.org/XML/1998/namespace}%s'
|
|
|
|
XSD_TEMPLATE = '{http://www.w3.org/2001/XMLSchema}%s'
|
|
|
|
XSI_TEMPLATE = '{http://www.w3.org/2001/XMLSchema-instance}%s'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
|
2019-07-30 21:06:54 +02:00
|
|
|
#
|
|
|
|
# Version Control attributes (XSD 1.1)
|
|
|
|
VC_MIN_VERSION = VC_TEMPLATE % 'minVersion'
|
|
|
|
VC_MAX_VERSION = VC_TEMPLATE % 'maxVersion'
|
2019-08-01 07:03:03 +02:00
|
|
|
VC_TYPE_AVAILABLE = VC_TEMPLATE % 'typeAvailable'
|
|
|
|
VC_TYPE_UNAVAILABLE = VC_TEMPLATE % 'typeUnavailable'
|
|
|
|
VC_FACET_AVAILABLE = VC_TEMPLATE % 'facetAvailable'
|
|
|
|
VC_FACET_UNAVAILABLE = VC_TEMPLATE % 'facetUnavailable'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
|
2018-10-08 23:47:18 +02:00
|
|
|
#
|
|
|
|
# XML attributes
|
2019-07-30 21:06:54 +02:00
|
|
|
XML_LANG = XML_TEMPLATE % 'lang'
|
|
|
|
XML_SPACE = XML_TEMPLATE % 'space'
|
|
|
|
XML_BASE = XML_TEMPLATE % 'base'
|
|
|
|
XML_ID = XML_TEMPLATE % 'id'
|
|
|
|
XML_SPECIAL_ATTRS = XML_TEMPLATE % 'specialAttrs'
|
|
|
|
|
2018-09-15 16:50:33 +02:00
|
|
|
|
2018-10-08 23:47:18 +02:00
|
|
|
#
|
|
|
|
# XML Schema Instance attributes
|
2019-07-30 21:06:54 +02:00
|
|
|
XSI_NIL = XSI_TEMPLATE % 'nil'
|
|
|
|
XSI_TYPE = XSI_TEMPLATE % 'type'
|
|
|
|
XSI_SCHEMA_LOCATION = XSI_TEMPLATE % 'schemaLocation'
|
|
|
|
XSI_NONS_SCHEMA_LOCATION = XSI_TEMPLATE % 'noNamespaceSchemaLocation'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
2017-06-07 17:16:32 +02:00
|
|
|
|
2017-05-23 16:45:10 +02:00
|
|
|
#
|
|
|
|
# XML Schema fully qualified names
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_SCHEMA = XSD_TEMPLATE % 'schema'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
# Annotations
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_ANNOTATION = XSD_TEMPLATE % 'annotation'
|
|
|
|
XSD_APPINFO = XSD_TEMPLATE % 'appinfo'
|
|
|
|
XSD_DOCUMENTATION = XSD_TEMPLATE % 'documentation'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
# Composing schemas
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_INCLUDE = XSD_TEMPLATE % 'include'
|
|
|
|
XSD_IMPORT = XSD_TEMPLATE % 'import'
|
|
|
|
XSD_REDEFINE = XSD_TEMPLATE % 'redefine'
|
|
|
|
XSD_OVERRIDE = XSD_TEMPLATE % 'override'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
# Structures
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_SIMPLE_TYPE = XSD_TEMPLATE % 'simpleType'
|
|
|
|
XSD_COMPLEX_TYPE = XSD_TEMPLATE % 'complexType'
|
|
|
|
XSD_ATTRIBUTE = XSD_TEMPLATE % 'attribute'
|
|
|
|
XSD_ELEMENT = XSD_TEMPLATE % 'element'
|
|
|
|
XSD_NOTATION = XSD_TEMPLATE % 'notation'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
# Grouping
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_GROUP = XSD_TEMPLATE % 'group'
|
|
|
|
XSD_ATTRIBUTE_GROUP = XSD_TEMPLATE % 'attributeGroup'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
# simpleType declaration elements
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_RESTRICTION = XSD_TEMPLATE % 'restriction'
|
|
|
|
XSD_LIST = XSD_TEMPLATE % 'list'
|
|
|
|
XSD_UNION = XSD_TEMPLATE % 'union'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
# complexType content
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_EXTENSION = XSD_TEMPLATE % 'extension'
|
|
|
|
XSD_SEQUENCE = XSD_TEMPLATE % 'sequence'
|
|
|
|
XSD_CHOICE = XSD_TEMPLATE % 'choice'
|
|
|
|
XSD_ALL = XSD_TEMPLATE % 'all'
|
|
|
|
XSD_ANY = XSD_TEMPLATE % 'any'
|
|
|
|
XSD_SIMPLE_CONTENT = XSD_TEMPLATE % 'simpleContent'
|
|
|
|
XSD_COMPLEX_CONTENT = XSD_TEMPLATE % 'complexContent'
|
|
|
|
XSD_ANY_ATTRIBUTE = XSD_TEMPLATE % 'anyAttribute'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
|
|
|
#
|
|
|
|
# Facets (lexical, pre-lexical and value-based facets)
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_ENUMERATION = XSD_TEMPLATE % 'enumeration'
|
|
|
|
XSD_LENGTH = XSD_TEMPLATE % 'length'
|
|
|
|
XSD_MIN_LENGTH = XSD_TEMPLATE % 'minLength'
|
|
|
|
XSD_MAX_LENGTH = XSD_TEMPLATE % 'maxLength'
|
|
|
|
XSD_PATTERN = XSD_TEMPLATE % 'pattern' # lexical facet
|
|
|
|
XSD_WHITE_SPACE = XSD_TEMPLATE % 'whiteSpace' # pre-lexical facet
|
|
|
|
XSD_MAX_INCLUSIVE = XSD_TEMPLATE % 'maxInclusive'
|
|
|
|
XSD_MAX_EXCLUSIVE = XSD_TEMPLATE % 'maxExclusive'
|
|
|
|
XSD_MIN_INCLUSIVE = XSD_TEMPLATE % 'minInclusive'
|
|
|
|
XSD_MIN_EXCLUSIVE = XSD_TEMPLATE % 'minExclusive'
|
|
|
|
XSD_TOTAL_DIGITS = XSD_TEMPLATE % 'totalDigits'
|
|
|
|
XSD_FRACTION_DIGITS = XSD_TEMPLATE % 'fractionDigits'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
2018-01-28 09:37:56 +01:00
|
|
|
# XSD 1.1 elements
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_OPEN_CONTENT = XSD_TEMPLATE % 'openContent' # open content model
|
|
|
|
XSD_DEFAULT_OPEN_CONTENT = XSD_TEMPLATE % 'defaultOpenContent' # default open content model (schema level)
|
|
|
|
XSD_ALTERNATIVE = XSD_TEMPLATE % 'alternative' # conditional type assignment
|
|
|
|
XSD_ASSERT = XSD_TEMPLATE % 'assert' # complex type assertions
|
|
|
|
XSD_ASSERTION = XSD_TEMPLATE % 'assertion' # facets
|
|
|
|
XSD_EXPLICIT_TIMEZONE = XSD_TEMPLATE % 'explicitTimezone'
|
2017-05-23 16:45:10 +02:00
|
|
|
|
2017-07-22 07:20:16 +02:00
|
|
|
# Identity constraints
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_UNIQUE = XSD_TEMPLATE % 'unique'
|
|
|
|
XSD_KEY = XSD_TEMPLATE % 'key'
|
|
|
|
XSD_KEYREF = XSD_TEMPLATE % 'keyref'
|
|
|
|
XSD_SELECTOR = XSD_TEMPLATE % 'selector'
|
|
|
|
XSD_FIELD = XSD_TEMPLATE % 'field'
|
2018-04-05 09:28:49 +02:00
|
|
|
|
2018-10-08 15:32:50 +02:00
|
|
|
#
|
|
|
|
# XSD Builtin Types
|
|
|
|
|
|
|
|
# Special XSD built-in types.
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_ANY_TYPE = XSD_TEMPLATE % 'anyType'
|
|
|
|
XSD_ANY_SIMPLE_TYPE = XSD_TEMPLATE % 'anySimpleType'
|
|
|
|
XSD_ANY_ATOMIC_TYPE = XSD_TEMPLATE % 'anyAtomicType'
|
2018-10-08 15:32:50 +02:00
|
|
|
|
|
|
|
# Other XSD built-in types.
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_DECIMAL = XSD_TEMPLATE % 'decimal'
|
|
|
|
XSD_STRING = XSD_TEMPLATE % 'string'
|
|
|
|
XSD_DOUBLE = XSD_TEMPLATE % 'double'
|
|
|
|
XSD_FLOAT = XSD_TEMPLATE % 'float'
|
|
|
|
|
|
|
|
XSD_DATE = XSD_TEMPLATE % 'date'
|
|
|
|
XSD_DATETIME = XSD_TEMPLATE % 'dateTime'
|
|
|
|
XSD_GDAY = XSD_TEMPLATE % 'gDay'
|
|
|
|
XSD_GMONTH = XSD_TEMPLATE % 'gMonth'
|
|
|
|
XSD_GMONTH_DAY = XSD_TEMPLATE % 'gMonthDay'
|
|
|
|
XSD_GYEAR = XSD_TEMPLATE % 'gYear'
|
|
|
|
XSD_GYEAR_MONTH = XSD_TEMPLATE % 'gYearMonth'
|
|
|
|
XSD_TIME = XSD_TEMPLATE % 'time'
|
|
|
|
XSD_DURATION = XSD_TEMPLATE % 'duration'
|
|
|
|
|
|
|
|
XSD_QNAME = XSD_TEMPLATE % 'QName'
|
|
|
|
XSD_NOTATION_TYPE = XSD_TEMPLATE % 'NOTATION'
|
|
|
|
XSD_ANY_URI = XSD_TEMPLATE % 'anyURI'
|
|
|
|
XSD_BOOLEAN = XSD_TEMPLATE % 'boolean'
|
|
|
|
XSD_BASE64_BINARY = XSD_TEMPLATE % 'base64Binary'
|
|
|
|
XSD_HEX_BINARY = XSD_TEMPLATE % 'hexBinary'
|
|
|
|
XSD_NORMALIZED_STRING = XSD_TEMPLATE % 'normalizedString'
|
|
|
|
XSD_TOKEN = XSD_TEMPLATE % 'token'
|
|
|
|
XSD_LANGUAGE = XSD_TEMPLATE % 'language'
|
|
|
|
XSD_NAME = XSD_TEMPLATE % 'Name'
|
|
|
|
XSD_NCNAME = XSD_TEMPLATE % 'NCName'
|
|
|
|
XSD_ID = XSD_TEMPLATE % 'ID'
|
|
|
|
XSD_IDREF = XSD_TEMPLATE % 'IDREF'
|
|
|
|
XSD_ENTITY = XSD_TEMPLATE % 'ENTITY'
|
|
|
|
XSD_NMTOKEN = XSD_TEMPLATE % 'NMTOKEN'
|
|
|
|
|
|
|
|
XSD_INTEGER = XSD_TEMPLATE % 'integer'
|
|
|
|
XSD_LONG = XSD_TEMPLATE % 'long'
|
|
|
|
XSD_INT = XSD_TEMPLATE % 'int'
|
|
|
|
XSD_SHORT = XSD_TEMPLATE % 'short'
|
|
|
|
XSD_BYTE = XSD_TEMPLATE % 'byte'
|
|
|
|
XSD_NON_NEGATIVE_INTEGER = XSD_TEMPLATE % 'nonNegativeInteger'
|
|
|
|
XSD_POSITIVE_INTEGER = XSD_TEMPLATE % 'positiveInteger'
|
|
|
|
XSD_UNSIGNED_LONG = XSD_TEMPLATE % 'unsignedLong'
|
|
|
|
XSD_UNSIGNED_INT = XSD_TEMPLATE % 'unsignedInt'
|
|
|
|
XSD_UNSIGNED_SHORT = XSD_TEMPLATE % 'unsignedShort'
|
|
|
|
XSD_UNSIGNED_BYTE = XSD_TEMPLATE % 'unsignedByte'
|
|
|
|
XSD_NON_POSITIVE_INTEGER = XSD_TEMPLATE % 'nonPositiveInteger'
|
|
|
|
XSD_NEGATIVE_INTEGER = XSD_TEMPLATE % 'negativeInteger'
|
2018-10-10 07:17:48 +02:00
|
|
|
|
2018-10-30 18:15:23 +01:00
|
|
|
# Built-in list types
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_IDREFS = XSD_TEMPLATE % 'IDREFS'
|
|
|
|
XSD_ENTITIES = XSD_TEMPLATE % 'ENTITIES'
|
|
|
|
XSD_NMTOKENS = XSD_TEMPLATE % 'NMTOKENS'
|
2018-10-30 18:15:23 +01:00
|
|
|
|
2018-10-10 07:17:48 +02:00
|
|
|
# XSD 1.1 built-in types
|
2019-07-30 21:06:54 +02:00
|
|
|
XSD_DATE_TIME_STAMP = XSD_TEMPLATE % 'dateTimeStamp'
|
|
|
|
XSD_DAY_TIME_DURATION = XSD_TEMPLATE % 'dayTimeDuration'
|
|
|
|
XSD_YEAR_MONTH_DURATION = XSD_TEMPLATE % 'yearMonthDuration'
|
2019-08-17 09:36:24 +02:00
|
|
|
XSD_ERROR = XSD_TEMPLATE % 'error'
|
2019-10-07 15:31:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
def get_qname(uri, name):
|
|
|
|
"""
|
|
|
|
Returns an expanded QName from URI and local part. If any argument has boolean value
|
|
|
|
`False` or if the name is already an expanded QName, returns the *name* argument.
|
|
|
|
|
|
|
|
:param uri: namespace URI
|
|
|
|
:param name: local or qualified name
|
|
|
|
:return: string or the name argument
|
|
|
|
"""
|
|
|
|
if not uri or not name or name[0] in ('{', '.', '/', '['):
|
|
|
|
return name
|
|
|
|
else:
|
|
|
|
return '{%s}%s' % (uri, name)
|
|
|
|
|
|
|
|
|
|
|
|
def local_name(qname):
|
|
|
|
"""
|
|
|
|
Return the local part of an expanded QName or a prefixed name. If the name
|
|
|
|
is `None` or empty returns the *name* argument.
|
|
|
|
|
|
|
|
:param qname: an expanded QName or a prefixed name or a local name.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
if qname[0] == '{':
|
|
|
|
_, qname = qname.split('}')
|
|
|
|
elif ':' in qname:
|
|
|
|
_, qname = qname.split(':')
|
|
|
|
except IndexError:
|
|
|
|
return ''
|
|
|
|
except ValueError:
|
|
|
|
raise XMLSchemaValueError("the argument 'qname' has a wrong format: %r" % qname)
|
|
|
|
except TypeError:
|
|
|
|
if qname is None:
|
|
|
|
return qname
|
|
|
|
raise XMLSchemaTypeError("the argument 'qname' must be a string-like object or None")
|
|
|
|
else:
|
|
|
|
return qname
|
|
|
|
|
|
|
|
|
2019-10-23 09:47:49 +02:00
|
|
|
def qname_to_prefixed(qname, namespaces, use_empty=True):
|
2019-10-07 15:31:18 +02:00
|
|
|
"""
|
2019-10-23 09:47:49 +02:00
|
|
|
Maps a QName in extended format to a QName in prefixed format.
|
|
|
|
Do not change local names and QNames in prefixed format.
|
2019-10-07 15:31:18 +02:00
|
|
|
|
2019-10-23 09:47:49 +02:00
|
|
|
:param qname: a QName or a local name.
|
2019-10-07 15:31:18 +02:00
|
|
|
:param namespaces: a map from prefixes to namespace URIs.
|
2019-10-23 09:47:49 +02:00
|
|
|
:param use_empty: if `True` use the empty prefix for mapping.
|
2019-10-07 15:31:18 +02:00
|
|
|
:return: a QName in prefixed format or a local name.
|
|
|
|
"""
|
2019-10-23 09:47:49 +02:00
|
|
|
if not qname or qname[0] != '{':
|
2019-10-07 15:31:18 +02:00
|
|
|
return qname
|
|
|
|
|
|
|
|
namespace = get_namespace(qname)
|
2019-10-23 09:47:49 +02:00
|
|
|
prefixes = [x for x in namespaces if namespaces[x] == namespace]
|
|
|
|
|
|
|
|
if not prefixes:
|
|
|
|
return qname
|
|
|
|
elif prefixes[0]:
|
|
|
|
return '%s:%s' % (prefixes[0], qname.split('}', 1)[1])
|
|
|
|
elif len(prefixes) > 1:
|
|
|
|
return '%s:%s' % (prefixes[1], qname.split('}', 1)[1])
|
|
|
|
elif use_empty:
|
|
|
|
return qname.split('}', 1)[1]
|
2019-10-07 15:31:18 +02:00
|
|
|
else:
|
|
|
|
return qname
|
|
|
|
|
|
|
|
|
|
|
|
def qname_to_extended(qname, namespaces):
|
|
|
|
"""
|
2019-10-23 09:47:49 +02:00
|
|
|
Maps a QName in prefixed format or a local name to the extended QName format.
|
|
|
|
Local names are mapped if *namespaces* has a not empty default namespace.
|
2019-10-07 15:31:18 +02:00
|
|
|
|
|
|
|
:param qname: a QName in prefixed format or a local name.
|
|
|
|
:param namespaces: a map from prefixes to namespace URIs.
|
|
|
|
:return: a QName in extended format or a local name.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
if qname[0] == '{' or not namespaces:
|
|
|
|
return qname
|
|
|
|
except IndexError:
|
|
|
|
return qname
|
|
|
|
|
|
|
|
try:
|
|
|
|
prefix, name = qname.split(':', 1)
|
|
|
|
except ValueError:
|
|
|
|
if not namespaces.get(''):
|
|
|
|
return qname
|
|
|
|
else:
|
|
|
|
return '{%s}%s' % (namespaces[''], qname)
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
uri = namespaces[prefix]
|
|
|
|
except KeyError:
|
|
|
|
return qname
|
|
|
|
else:
|
|
|
|
return u'{%s}%s' % (uri, name) if uri else name
|