#!/usr/bin/env python # Copyright (c) 2003, The Regents of the University of California, # through Lawrence Berkeley National Laboratory (subject to receipt of # any required approvals from the U.S. Dept. of Energy). All rights # reserved. # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. ident = "$Id$" import logging import sys import types import warnings import weakref from six import string_types from .Namespaces import APACHE from .Namespaces import SCHEMA from .Namespaces import SOAP from .Namespaces import XMLNS from .Utility import DOM from .Utility import Collection from .Utility import DOMException from .Utility import SplitQName from .Utility import basejoin try: from io import StringIO except ImportError: # from io import StringIO from io import BytesIO as StringIO # If we have no threading, this should be a no-op try: from threading import RLock except ImportError: class RLock(object): def acquire(): pass def release(): pass # # Collections in XMLSchema class # TYPES = 'types' ATTRIBUTE_GROUPS = 'attr_groups' ATTRIBUTES = 'attr_decl' ELEMENTS = 'elements' MODEL_GROUPS = 'model_groups' BUILT_IN_NAMESPACES = [SOAP.ENC, ] + SCHEMA.XSD_LIST + [APACHE.AXIS_NS] def GetSchema(component): """convience function for finding the parent XMLSchema instance. """ parent = component while not isinstance(parent, XMLSchema): parent = parent._parent() return parent class SchemaReader(object): """A SchemaReader creates XMLSchema objects from urls and xml data. """ namespaceToSchema = {} def __init__(self, domReader=None, base_url=None): """domReader -- class must implement DOMAdapterInterface base_url -- base url string """ self.__base_url = base_url self.__readerClass = domReader if not self.__readerClass: self.__readerClass = DOMAdapter self._includes = {} self._imports = {} def __setImports(self, schema): """Add dictionary of imports to schema instance. schema -- XMLSchema instance """ for ns, val in list(schema.imports.items()): if ns in self._imports: schema.addImportSchema(self._imports[ns]) def __setIncludes(self, schema): """Add dictionary of includes to schema instance. schema -- XMLSchema instance """ for schemaLocation, val in list(schema.includes.items()): if schemaLocation in self._includes: schema.addIncludeSchema( schemaLocation, self._imports[schemaLocation]) def addSchemaByLocation(self, location, schema): """provide reader with schema document for a location. """ self._includes[location] = schema def addSchemaByNamespace(self, schema): """provide reader with schema document for a targetNamespace. """ self._imports[schema.targetNamespace] = schema def loadFromNode(self, parent, element): """element -- DOM node or document parent -- WSDLAdapter instance """ reader = self.__readerClass(element) schema = XMLSchema(parent) # HACK to keep a reference schema.wsdl = parent schema.setBaseUrl(self.__base_url) schema.load(reader) return schema def loadFromStream(self, file, url=None): """Return an XMLSchema instance loaded from a file object. file -- file object url -- base location for resolving imports/includes. """ reader = self.__readerClass() reader.loadDocument(file) schema = XMLSchema() if url is not None: schema.setBaseUrl(url) schema.load(reader) self.__setIncludes(schema) self.__setImports(schema) return schema def loadFromString(self, data): """Return an XMLSchema instance loaded from an XML string. data -- XML string """ return self.loadFromStream(StringIO(data)) def loadFromURL(self, url, schema=None): """Return an XMLSchema instance loaded from the given url. url -- URL to dereference schema -- Optional XMLSchema instance. """ reader = self.__readerClass() if self.__base_url: url = basejoin(self.__base_url, url) reader.loadFromURL(url) schema = schema or XMLSchema() schema.setBaseUrl(url) schema.load(reader) self.__setIncludes(schema) self.__setImports(schema) return schema def loadFromFile(self, filename): """Return an XMLSchema instance loaded from the given file. filename -- name of file to open """ if self.__base_url: filename = basejoin(self.__base_url, filename) file = open(filename, 'rb') try: schema = self.loadFromStream(file, filename) finally: file.close() return schema class SchemaError(Exception): pass class NoSchemaLocationWarning(Exception): pass ########################### # DOM Utility Adapters ########################## class DOMAdapterInterface(object): def hasattr(self, attr, ns=None): """return true if node has attribute attr -- attribute to check for ns -- namespace of attribute, by default None """ raise NotImplementedError('adapter method not implemented') def getContentList(self, *contents): """returns an ordered list of child nodes *contents -- list of node names to return """ raise NotImplementedError('adapter method not implemented') def setAttributeDictionary(self, attributes): """set attribute dictionary """ raise NotImplementedError('adapter method not implemented') def getAttributeDictionary(self): """returns a dict of node's attributes """ raise NotImplementedError('adapter method not implemented') def getNamespace(self, prefix): """returns namespace referenced by prefix. """ raise NotImplementedError('adapter method not implemented') def getTagName(self): """returns tagName of node """ raise NotImplementedError('adapter method not implemented') def getParentNode(self): """returns parent element in DOMAdapter or None """ raise NotImplementedError('adapter method not implemented') def loadDocument(self, file): """load a Document from a file object file -- """ raise NotImplementedError('adapter method not implemented') def loadFromURL(self, url): """load a Document from an url url -- URL to dereference """ raise NotImplementedError('adapter method not implemented') class DOMAdapter(DOMAdapterInterface): """Adapter for ZSI.Utility.DOM """ def __init__(self, node=None): """Reset all instance variables. element -- DOM document, node, or None """ if hasattr(node, 'documentElement'): self.__node = node.documentElement else: self.__node = node self.__attributes = None def getNode(self): return self.__node def hasattr(self, attr, ns=None): """attr -- attribute ns -- optional namespace, None means unprefixed attribute. """ if not self.__attributes: self.setAttributeDictionary() if ns: return attr in self.__attributes.get(ns, {}) return attr in self.__attributes def getContentList(self, *contents): nodes = [] ELEMENT_NODE = self.__node.ELEMENT_NODE for child in DOM.getElements(self.__node, None): if child.nodeType == ELEMENT_NODE and\ SplitQName(child.tagName)[1] in contents: nodes.append(child) return list(map(self.__class__, nodes)) def setAttributeDictionary(self): self.__attributes = {} if self.__node._attrs: for v in list(self.__node._attrs.values()): self.__attributes[v.nodeName] = v.nodeValue def getAttributeDictionary(self): if not self.__attributes: self.setAttributeDictionary() return self.__attributes def getTagName(self): return self.__node.tagName def getParentNode(self): if self.__node.parentNode.nodeType == self.__node.ELEMENT_NODE: return DOMAdapter(self.__node.parentNode) return None def getNamespace(self, prefix): """prefix -- deference namespace prefix in node's context. Ascends parent nodes until found. """ namespace = None if prefix == 'xmlns': namespace = DOM.findDefaultNS(prefix, self.__node) else: try: namespace = DOM.findNamespaceURI(prefix, self.__node) except DOMException: if prefix != 'xml': raise SchemaError('%s namespace not declared for %s' % ( prefix, self.__node._get_tagName())) namespace = XMLNS.XML return namespace def loadDocument(self, file): self.__node = DOM.loadDocument(file) if hasattr(self.__node, 'documentElement'): self.__node = self.__node.documentElement def loadFromURL(self, url): self.__node = DOM.loadFromURL(url) if hasattr(self.__node, 'documentElement'): self.__node = self.__node.documentElement class XMLBase: """ These class variables are for string indentation. """ tag = None __indent = 0 __rlock = RLock() def __str__(self): XMLBase.__rlock.acquire() XMLBase.__indent += 1 tmp = "<" + str(self.__class__) + '>\n' for k, v in list(self.__dict__.items()): tmp += "%s* %s = %s\n" % (XMLBase.__indent * ' ', k, v) XMLBase.__indent -= 1 XMLBase.__rlock.release() return tmp """Marker Interface: can determine something about an instances properties by using the provided convenience functions. """ class DefinitionMarker: """marker for definitions """ pass class DeclarationMarker: """marker for declarations """ pass class AttributeMarker: """marker for attributes """ pass class AttributeGroupMarker: """marker for attribute groups """ pass class WildCardMarker: """marker for wildcards """ pass class ElementMarker: """marker for wildcards """ pass class ReferenceMarker: """marker for references """ pass class ModelGroupMarker: """marker for model groups """ pass class AllMarker(ModelGroupMarker): """marker for all model group """ pass class ChoiceMarker(ModelGroupMarker): """marker for choice model group """ pass class SequenceMarker(ModelGroupMarker): """marker for sequence model group """ pass class ExtensionMarker: """marker for extensions """ pass class RestrictionMarker: """marker for restrictions """ facets = ['enumeration', 'length', 'maxExclusive', 'maxInclusive', 'maxLength', 'minExclusive', 'minInclusive', 'minLength', 'pattern', 'fractionDigits', 'totalDigits', 'whiteSpace'] class SimpleMarker: """marker for simple type information """ pass class ListMarker: """marker for simple type list """ pass class UnionMarker: """marker for simple type Union """ pass class ComplexMarker: """marker for complex type information """ pass class LocalMarker: """marker for complex type information """ pass class MarkerInterface: def isDefinition(self): return isinstance(self, DefinitionMarker) def isDeclaration(self): return isinstance(self, DeclarationMarker) def isAttribute(self): return isinstance(self, AttributeMarker) def isAttributeGroup(self): return isinstance(self, AttributeGroupMarker) def isElement(self): return isinstance(self, ElementMarker) def isReference(self): return isinstance(self, ReferenceMarker) def isWildCard(self): return isinstance(self, WildCardMarker) def isModelGroup(self): return isinstance(self, ModelGroupMarker) def isAll(self): return isinstance(self, AllMarker) def isChoice(self): return isinstance(self, ChoiceMarker) def isSequence(self): return isinstance(self, SequenceMarker) def isExtension(self): return isinstance(self, ExtensionMarker) def isRestriction(self): return isinstance(self, RestrictionMarker) def isSimple(self): return isinstance(self, SimpleMarker) def isComplex(self): return isinstance(self, ComplexMarker) def isLocal(self): return isinstance(self, LocalMarker) def isList(self): return isinstance(self, ListMarker) def isUnion(self): return isinstance(self, UnionMarker) ########################################################## # Schema Components ######################################################### class XMLSchemaComponent(XMLBase, MarkerInterface): """ class variables: required -- list of required attributes attributes -- dict of default attribute values, including None. Value can be a function for runtime dependencies. contents -- dict of namespace keyed content lists. 'xsd' content of xsd namespace. xmlns_key -- key for declared xmlns namespace. xmlns -- xmlns is special prefix for namespace dictionary xml -- special xml prefix for xml namespace. """ required = [] attributes = {} contents = {} xmlns_key = '' xmlns = 'xmlns' xml = 'xml' def __init__(self, parent=None): """parent -- parent instance instance variables: attributes -- dictionary of node's attributes """ self.attributes = None self._parent = parent if self._parent: self._parent = weakref.ref(parent) if not self.__class__ == XMLSchemaComponent\ and not (isinstance(self.__class__.required, type(XMLSchemaComponent.required)) and isinstance(self.__class__.attributes, type(XMLSchemaComponent.attributes)) and isinstance(self.__class__.contents, type(XMLSchemaComponent.contents))): raise RuntimeError( 'Bad type for a class variable in %s' % self.__class__) def getItemTrace(self): """Returns a node trace up to the item. """ item, path, name, ref = self, [], 'name', 'ref' while not isinstance(item, XMLSchema) and not isinstance(item, WSDLToolsAdapter): attr = item.getAttribute(name) if not attr: attr = item.getAttribute(ref) if not attr: path.append('<%s>' % (item.tag)) else: path.append('<%s ref="%s">' % (item.tag, attr)) else: path.append('<%s name="%s">' % (item.tag, attr)) item = item._parent() try: tns = item.getTargetNamespace() except: tns = '' path.append('<%s targetNamespace="%s">' % (item.tag, tns)) path.reverse() return ''.join(path) def getTargetNamespace(self): """return targetNamespace """ parent = self targetNamespace = 'targetNamespace' tns = self.attributes.get(targetNamespace) while not tns and parent and parent._parent is not None: parent = parent._parent() tns = parent.attributes.get(targetNamespace) return tns or '' def getAttributeDeclaration(self, attribute): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return self.getQNameAttribute(ATTRIBUTES, attribute) def getAttributeGroup(self, attribute): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return self.getQNameAttribute(ATTRIBUTE_GROUPS, attribute) def getTypeDefinition(self, attribute): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return self.getQNameAttribute(TYPES, attribute) def getElementDeclaration(self, attribute): """attribute -- attribute with a QName value (eg. element). collection -- check elements collection in parent Schema instance. """ return self.getQNameAttribute(ELEMENTS, attribute) def getModelGroup(self, attribute): """attribute -- attribute with a QName value (eg. ref). collection -- check model_group collection in parent Schema instance. """ return self.getQNameAttribute(MODEL_GROUPS, attribute) def getQNameAttribute(self, collection, attribute): """returns object instance representing QName --> (namespace,name), or if does not exist return None. attribute -- an information item attribute, with a QName value. collection -- collection in parent Schema instance to search. """ tdc = self.getAttributeQName(attribute) if not tdc: return obj = self.getSchemaItem( collection, tdc.getTargetNamespace(), tdc.getName()) if obj: return obj # raise SchemaError, 'No schema item "%s" in collection %s' %(tdc, # collection) return def getSchemaItem(self, collection, namespace, name): """returns object instance representing namespace, name, or if does not exist return None if built-in, else raise SchemaError. namespace -- namespace item defined in. name -- name of item. collection -- collection in parent Schema instance to search. """ parent = GetSchema(self) if parent.targetNamespace == namespace: try: obj = getattr(parent, collection)[name] except KeyError: raise KeyError('targetNamespace(%s) collection(%s) has no item(%s)' % ( namespace, collection, name)) return obj if namespace not in parent.imports: if namespace in BUILT_IN_NAMESPACES: # built-in just return # WARNING: expecting import if "redefine" or add to built-in # namespace. return raise SchemaError('schema "%s" does not import namespace "%s"' % ( parent.targetNamespace, namespace)) # Lazy Eval schema = parent.imports[namespace] if not isinstance(schema, XMLSchema): schema = schema.getSchema() if schema is not None: parent.imports[namespace] = schema if schema is None: if namespace in BUILT_IN_NAMESPACES: # built-in just return return raise SchemaError( 'no schema instance for imported namespace (%s).' % (namespace)) if not isinstance(schema, XMLSchema): raise TypeError('expecting XMLSchema instance not "%r"' % schema) try: obj = getattr(schema, collection)[name] except KeyError: raise KeyError('targetNamespace(%s) collection(%s) has no item(%s)' % ( namespace, collection, name)) return obj def getXMLNS(self, prefix=None): """deference prefix or by default xmlns, returns namespace. """ if prefix == XMLSchemaComponent.xml: return XMLNS.XML parent = self ns = self.attributes[XMLSchemaComponent.xmlns].get(prefix or XMLSchemaComponent.xmlns_key) while not ns: parent = parent._parent() ns = parent.attributes[XMLSchemaComponent.xmlns].get(prefix or XMLSchemaComponent.xmlns_key) if not ns and isinstance(parent, WSDLToolsAdapter): if prefix is None: return '' raise SchemaError('unknown prefix %s' % prefix) return ns def getAttribute(self, attribute): """return requested attribute value or None """ if type(attribute) in (list, tuple): if len(attribute) != 2: raise LookupError( 'To access attributes must use name or (namespace,name)') ns_dict = self.attributes.get(attribute[0]) if ns_dict is None: return None return ns_dict.get(attribute[1]) return self.attributes.get(attribute) def getAttributeQName(self, attribute): """return requested attribute value as (namespace,name) or None """ qname = self.getAttribute(attribute) if isinstance(qname, TypeDescriptionComponent) is True: return qname if qname is None: return None prefix, ncname = SplitQName(qname) namespace = self.getXMLNS(prefix) return TypeDescriptionComponent((namespace, ncname)) def getAttributeName(self): """return attribute name or None """ return self.getAttribute('name') def setAttributes(self, node): """Sets up attribute dictionary, checks for required attributes and sets default attribute values. attr is for default attribute values determined at runtime. structure of attributes dictionary ['xmlns'][xmlns_key] -- xmlns namespace ['xmlns'][prefix] -- declared namespace prefix [namespace][prefix] -- attributes declared in a namespace [attribute] -- attributes w/o prefix, default namespaces do not directly apply to attributes, ie Name can't collide with QName. """ self.attributes = {XMLSchemaComponent.xmlns: {}} for k, v in list(node.getAttributeDictionary().items()): prefix, value = SplitQName(k) if value == XMLSchemaComponent.xmlns: self.attributes[value][ prefix or XMLSchemaComponent.xmlns_key] = v elif prefix: ns = node.getNamespace(prefix) if not ns: raise SchemaError( 'no namespace for attribute prefix %s' % prefix) if ns not in self.attributes: self.attributes[ns] = {} elif value in self.attributes[ns]: raise SchemaError( 'attribute %s declared multiple times in %s' % (value, ns)) self.attributes[ns][value] = v elif value not in self.attributes: self.attributes[value] = v else: raise SchemaError( 'attribute %s declared multiple times' % value) if not isinstance(self, WSDLToolsAdapter): self.__checkAttributes() self.__setAttributeDefaults() # set QNames for k in ['type', 'element', 'base', 'ref', 'substitutionGroup', 'itemType']: if k in self.attributes: prefix, value = SplitQName(self.attributes.get(k)) self.attributes[k] = \ TypeDescriptionComponent((self.getXMLNS(prefix), value)) # Union, memberTypes is a whitespace separated list of QNames for k in ['memberTypes']: if k in self.attributes: qnames = self.attributes[k] self.attributes[k] = [] for qname in qnames.split(): prefix, value = SplitQName(qname) self.attributes['memberTypes'].append( TypeDescriptionComponent( (self.getXMLNS(prefix), value))) def getContents(self, node): """retrieve xsd contents """ return node.getContentList(*self.__class__.contents['xsd']) def __setAttributeDefaults(self): """Looks for default values for unset attributes. If class variable representing attribute is None, then it must be defined as an instance variable. """ for k, v in list(self.__class__.attributes.items()): if v is not None and k in self.attributes is False: if isinstance(v, types.FunctionType): self.attributes[k] = v(self) else: self.attributes[k] = v def __checkAttributes(self): """Checks that required attributes have been defined, attributes w/default cannot be required. Checks all defined attributes are legal, attribute references are not subject to this test. """ for a in self.__class__.required: if a not in self.attributes: raise SchemaError( 'class instance %s, missing required attribute %s' % (self.__class__, a)) for a, v in list(self.attributes.items()): # attribute #other, ie. not in empty namespace if type(v) is dict: continue # predefined prefixes xmlns, xml if a in (XMLSchemaComponent.xmlns, XMLNS.XML): continue if (a not in list(self.__class__.attributes.keys())) and not\ (self.isAttribute() and self.isReference()): raise SchemaError('%s, unknown attribute(%s, %s)' % ( self.getItemTrace(), a, self.attributes[a])) class WSDLToolsAdapter(XMLSchemaComponent): """WSDL Adapter to grab the attributes from the wsdl document node. """ attributes = {'name': None, 'targetNamespace': None} tag = 'definitions' def __init__(self, wsdl): XMLSchemaComponent.__init__(self, parent=wsdl) self.setAttributes(DOMAdapter(wsdl.document)) def getImportSchemas(self): """returns WSDLTools.WSDL types Collection """ return self._parent().types class Notation(XMLSchemaComponent): """ parent: schema attributes: id -- ID name -- NCName, Required public -- token, Required system -- anyURI contents: annotation? """ required = ['name', 'public'] attributes = {'id': None, 'name': None, 'public': None, 'system': None} contents = {'xsd': ('annotation')} tag = 'notation' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class Annotation(XMLSchemaComponent): """ parent: all,any,anyAttribute,attribute,attributeGroup,choice,complexContent, complexType,element,extension,field,group,import,include,key,keyref, list,notation,redefine,restriction,schema,selector,simpleContent, simpleType,union,unique attributes: id -- ID contents: (documentation | appinfo)* """ attributes = {'id': None} contents = {'xsd': ('documentation', 'appinfo')} tag = 'annotation' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component == 'documentation': # print_debug('class %s, documentation skipped' %self.__class__, 5) continue elif component == 'appinfo': # print_debug('class %s, appinfo skipped' %self.__class__, 5) continue else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.content = tuple(content) class Documentation(XMLSchemaComponent): """ parent: annotation attributes: source, anyURI xml:lang, language contents: mixed, any """ attributes = {'source': None, 'xml: lang': None} contents = {'xsd': ('mixed', 'any')} tag = 'documentation' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component == 'mixed': # print_debug('class %s, mixed skipped' %self.__class__, 5) continue elif component == 'any': # print_debug('class %s, any skipped' %self.__class__, 5) continue else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.content = tuple(content) class Appinfo(XMLSchemaComponent): """ parent: annotation attributes: source, anyURI contents: mixed, any """ attributes = {'source': None, 'anyURI': None} contents = {'xsd': ('mixed', 'any')} tag = 'appinfo' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component == 'mixed': # print_debug('class %s, mixed skipped' %self.__class__, 5) continue elif component == 'any': # print_debug('class %s, any skipped' %self.__class__, 5) continue else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.content = tuple(content) class XMLSchemaFake: # This is temporary, for the benefit of WSDL until the real thing works. def __init__(self, element): self.targetNamespace = DOM.getAttr(element, 'targetNamespace') self.element = element class XMLSchema(XMLSchemaComponent): """A schema is a collection of schema components derived from one or more schema documents, that is, one or more element information items. It represents the abstract notion of a schema rather than a single schema document (or other representation). parent: ROOT attributes: id -- ID version -- token xml:lang -- language targetNamespace -- anyURI attributeFormDefault -- 'qualified' | 'unqualified', 'unqualified' elementFormDefault -- 'qualified' | 'unqualified', 'unqualified' blockDefault -- '#all' | list of ('substitution | 'extension' | 'restriction') finalDefault -- '#all' | list of ('extension' | 'restriction' | 'list' | 'union') contents: ((include | import | redefine | annotation)*, (attribute, attributeGroup, complexType, element, group, notation, simpleType)*, annotation*)* attributes -- schema attributes imports -- import statements includes -- include statements redefines -- types -- global simpleType, complexType definitions elements -- global element declarations attr_decl -- global attribute declarations attr_groups -- attribute Groups model_groups -- model Groups notations -- global notations """ attributes = {'id': None, 'version': None, 'xml: lang': None, 'targetNamespace': None, 'attributeFormDefault': 'unqualified', 'elementFormDefault': 'unqualified', 'blockDefault': None, 'finalDefault': None} contents = {'xsd': ('include', 'import', 'redefine', 'annotation', 'attribute', 'attributeGroup', 'complexType', 'element', 'group', 'notation', 'simpleType', 'annotation')} empty_namespace = '' tag = 'schema' def __init__(self, parent=None, logger=None): """parent -- instance variables: targetNamespace -- schema's declared targetNamespace, or empty string. _imported_schemas -- namespace keyed dict of schema dependencies, if a schema is provided instance will not resolve import statement. _included_schemas -- schemaLocation keyed dict of component schemas, if schema is provided instance will not resolve include statement. _base_url -- needed for relative URLs support, only works with URLs relative to initial document. includes -- collection of include statements imports -- collection of import statements elements -- collection of global element declarations types -- collection of global type definitions attr_decl -- collection of global attribute declarations attr_groups -- collection of global attribute group definitions model_groups -- collection of model group definitions notations -- collection of notations """ self.__node = None self.targetNamespace = None XMLSchemaComponent.__init__(self, parent) f = lambda k: k.attributes['name'] ns = lambda k: k.attributes['namespace'] sl = lambda k: k.attributes['schemaLocation'] self.includes = Collection(self, key=sl) self.imports = Collection(self, key=ns) self.elements = Collection(self, key=f) self.types = Collection(self, key=f) self.attr_decl = Collection(self, key=f) self.attr_groups = Collection(self, key=f) self.model_groups = Collection(self, key=f) self.notations = Collection(self, key=f) self._imported_schemas = {} self._included_schemas = {} self._base_url = None self.logger = logger or logging.getLogger(__name__) def getNode(self): """ Interacting with the underlying DOM tree. """ return self.__node def addImportSchema(self, schema): """for resolving import statements in Schema instance schema -- schema instance _imported_schemas """ if not isinstance(schema, XMLSchema): raise TypeError('expecting a Schema instance') if schema.targetNamespace != self.targetNamespace: self._imported_schemas[schema.targetNamespace] = schema else: raise SchemaError('import schema bad targetNamespace') def addIncludeSchema(self, schemaLocation, schema): """for resolving include statements in Schema instance schemaLocation -- schema location schema -- schema instance _included_schemas """ if not isinstance(schema, XMLSchema): raise TypeError('expecting a Schema instance') if not schema.targetNamespace or\ schema.targetNamespace == self.targetNamespace: self._included_schemas[schemaLocation] = schema else: raise SchemaError('include schema bad targetNamespace') def setImportSchemas(self, schema_dict): """set the import schema dictionary, which is used to reference depedent schemas. """ self._imported_schemas = schema_dict def getImportSchemas(self): """get the import schema dictionary, which is used to reference depedent schemas. """ return self._imported_schemas def getSchemaNamespacesToImport(self): """returns tuple of namespaces the schema instance has declared itself to be depedent upon. """ return tuple(self.includes.keys()) def setIncludeSchemas(self, schema_dict): """set the include schema dictionary, which is keyed with schemaLocation (uri). This is a means of providing schemas to the current schema for content inclusion. """ self._included_schemas = schema_dict def getIncludeSchemas(self): """get the include schema dictionary, which is keyed with schemaLocation (uri). """ return self._included_schemas def getBaseUrl(self): """get base url, used for normalizing all relative uri's """ return self._base_url def setBaseUrl(self, url): """set base url, used for normalizing all relative uri's """ self._base_url = url def getElementFormDefault(self): """return elementFormDefault attribute """ return self.attributes.get('elementFormDefault') def isElementFormDefaultQualified(self): return self.attributes.get('elementFormDefault') == 'qualified' def getAttributeFormDefault(self): """return attributeFormDefault attribute """ return self.attributes.get('attributeFormDefault') def getBlockDefault(self): """return blockDefault attribute """ return self.attributes.get('blockDefault') def getFinalDefault(self): """return finalDefault attribute """ return self.attributes.get('finalDefault') def load(self, node, location=None): self.__node = node pnode = node.getParentNode() if pnode: pname = SplitQName(pnode.getTagName())[1] if pname == 'types': attributes = {} self.setAttributes(pnode) attributes.update(self.attributes) self.setAttributes(node) for k, v in list(attributes['xmlns'].items()): if k not in self.attributes['xmlns']: self.attributes['xmlns'][k] = v else: self.setAttributes(node) else: self.setAttributes(node) self.targetNamespace = self.getTargetNamespace() for childNode in self.getContents(node): component = SplitQName(childNode.getTagName())[1] if component == 'include': tp = self.__class__.Include(self) tp.fromDom(childNode) sl = tp.attributes['schemaLocation'] schema = tp.getSchema() if sl not in self.getIncludeSchemas(): self.addIncludeSchema(sl, schema) self.includes[sl] = tp pn = childNode.getParentNode().getNode() pn.removeChild(childNode.getNode()) for child in schema.getNode().getNode().childNodes: pn.appendChild(child.cloneNode(1)) for collection in ['imports', 'elements', 'types', 'attr_decl', 'attr_groups', 'model_groups', 'notations']: for k, v in list(getattr(schema, collection).items()): if k not in getattr(self, collection): v._parent = weakref.ref(self) getattr(self, collection)[k] = v else: warnings.warn("Not keeping schema component.") elif component == 'import': slocd = SchemaReader.namespaceToSchema tp = self.__class__.Import(self) tp.fromDom(childNode) import_ns = tp.getAttribute('namespace') or\ self.__class__.empty_namespace schema = slocd.get(import_ns) if schema is None: schema = XMLSchema() slocd[import_ns] = schema try: tp.loadSchema(schema) except NoSchemaLocationWarning as ex: # Dependency declaration, hopefully implementation # is aware of this namespace (eg. SOAP,WSDL,?) self.logger.debug("IMPORT: %s : %s" % (import_ns, ex)) del slocd[import_ns] continue except SchemaError as ex: # warnings.warn(\ # ', %s'\ # %(import_ns, 'failed to load schema instance') # ) self.logger.debug(ex) del slocd[import_ns] class _LazyEvalImport(str): '''Lazy evaluation of import, replace entry in self.imports.''' # attributes = dict(namespace=import_ns) def getSchema(namespace): schema = slocd.get(namespace) if schema is None: parent = self._parent() wstypes = parent if isinstance(parent, WSDLToolsAdapter): wstypes = parent.getImportSchemas() schema = wstypes.get(namespace) if isinstance(schema, XMLSchema): self.imports[namespace] = schema return schema return None self.imports[import_ns] = _LazyEvalImport(import_ns) continue else: tp._schema = schema if import_ns in self.getImportSchemas(): warnings.warn( 'Detected multiple imports of the namespace "%s" ' % import_ns) self.addImportSchema(schema) # spec says can have multiple imports of same namespace # but purpose of import is just dependency declaration. self.imports[import_ns] = tp elif component == 'redefine': warnings.warn('redefine is ignored') elif component == 'annotation': warnings.warn('annotation is ignored') elif component == 'attribute': tp = AttributeDeclaration(self) tp.fromDom(childNode) self.attr_decl[tp.getAttribute('name')] = tp elif component == 'attributeGroup': tp = AttributeGroupDefinition(self) tp.fromDom(childNode) self.attr_groups[tp.getAttribute('name')] = tp elif component == 'element': tp = ElementDeclaration(self) tp.fromDom(childNode) self.elements[tp.getAttribute('name')] = tp elif component == 'group': tp = ModelGroupDefinition(self) tp.fromDom(childNode) self.model_groups[tp.getAttribute('name')] = tp elif component == 'notation': tp = Notation(self) tp.fromDom(childNode) self.notations[tp.getAttribute('name')] = tp elif component == 'complexType': tp = ComplexType(self) tp.fromDom(childNode) self.types[tp.getAttribute('name')] = tp elif component == 'simpleType': tp = SimpleType(self) tp.fromDom(childNode) self.types[tp.getAttribute('name')] = tp else: break class Import(XMLSchemaComponent): """ parent: schema attributes: id -- ID namespace -- anyURI schemaLocation -- anyURI contents: annotation? """ attributes = {'id': None, 'namespace': None, 'schemaLocation': None} contents = {'xsd': ['annotation']} tag = 'import' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self._schema = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) if self.attributes['namespace'] == self.getTargetNamespace(): raise SchemaError('namespace of schema and import match') for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) def getSchema(self): """if schema is not defined, first look for a Schema class instance in parent Schema. Else if not defined resolve schemaLocation and create a new Schema class instance, and keep a hard reference. """ if not self._schema: ns = self.attributes['namespace'] schema = self._parent().getImportSchemas().get(ns) if not schema and self._parent()._parent: schema = self._parent()._parent().getImportSchemas().get(ns) if not schema: url = self.attributes.get('schemaLocation') if not url: raise SchemaError('namespace(%s) is unknown' % ns) base_url = self._parent().getBaseUrl() reader = SchemaReader(base_url=base_url) reader._imports = self._parent().getImportSchemas() reader._includes = self._parent().getIncludeSchemas() self._schema = reader.loadFromURL(url) return self._schema or schema def loadSchema(self, schema): """ """ base_url = self._parent().getBaseUrl() reader = SchemaReader(base_url=base_url) reader._imports = self._parent().getImportSchemas() reader._includes = self._parent().getIncludeSchemas() self._schema = schema if 'schemaLocation' not in self.attributes: raise NoSchemaLocationWarning( 'no schemaLocation attribute in import') reader.loadFromURL(self.attributes.get('schemaLocation'), schema) class Include(XMLSchemaComponent): """ parent: schema attributes: id -- ID schemaLocation -- anyURI, required contents: annotation? """ required = ['schemaLocation'] attributes = {'id': None, 'schemaLocation': None} contents = {'xsd': ['annotation']} tag = 'include' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self._schema = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) def getSchema(self): """if schema is not defined, first look for a Schema class instance in parent Schema. Else if not defined resolve schemaLocation and create a new Schema class instance. """ if not self._schema: schema = self._parent() self._schema = schema.getIncludeSchemas().get( self.attributes['schemaLocation']) if not self._schema: url = self.attributes['schemaLocation'] reader = SchemaReader(base_url=schema.getBaseUrl()) reader._imports = schema.getImportSchemas() reader._includes = schema.getIncludeSchemas() # create schema before loading so chameleon include # will evalute targetNamespace correctly. self._schema = XMLSchema(schema) reader.loadFromURL(url, self._schema) return self._schema class AttributeDeclaration(XMLSchemaComponent, AttributeMarker, DeclarationMarker): """ parent: schema attributes: id -- ID name -- NCName, required type -- QName default -- string fixed -- string contents: annotation?, simpleType? """ required = ['name'] attributes = {'id': None, 'name': None, 'type': None, 'default': None, 'fixed': None} contents = {'xsd': ['annotation', 'simpleType']} tag = 'attribute' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): """ No list or union support """ self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'simpleType': self.content = AnonymousSimpleType(self) self.content.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class LocalAttributeDeclaration(AttributeDeclaration, AttributeMarker, LocalMarker, DeclarationMarker): """ parent: complexType, restriction, extension, attributeGroup attributes: id -- ID name -- NCName, required type -- QName form -- ('qualified' | 'unqualified'), schema.attributeFormDefault use -- ('optional' | 'prohibited' | 'required'), optional default -- string fixed -- string contents: annotation?, simpleType? """ required = ['name'] attributes = {'id': None, 'name': None, 'type': None, 'form': lambda self: GetSchema(self).getAttributeFormDefault(), 'use': 'optional', 'default': None, 'fixed': None} contents = {'xsd': ['annotation', 'simpleType']} def __init__(self, parent): AttributeDeclaration.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'simpleType': self.content = AnonymousSimpleType(self) self.content.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class AttributeWildCard(XMLSchemaComponent, AttributeMarker, DeclarationMarker, WildCardMarker): """ parents: complexType, restriction, extension, attributeGroup attributes: id -- ID namespace -- '##any' | '##other' | (anyURI* | '##targetNamespace' | '##local'), ##any processContents -- 'lax' | 'skip' | 'strict', strict contents: annotation? """ attributes = {'id': None, 'namespace': '##any', 'processContents': 'strict'} contents = {'xsd': ['annotation']} tag = 'anyAttribute' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class AttributeReference(XMLSchemaComponent, AttributeMarker, ReferenceMarker): """ parents: complexType, restriction, extension, attributeGroup attributes: id -- ID ref -- QName, required use -- ('optional' | 'prohibited' | 'required'), optional default -- string fixed -- string contents: annotation? """ required = ['ref'] attributes = {'id': None, 'ref': None, 'use': 'optional', 'default': None, 'fixed': None} contents = {'xsd': ['annotation']} tag = 'attribute' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getAttributeDeclaration(self, attribute='ref'): return XMLSchemaComponent.getAttributeDeclaration(self, attribute) def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class AttributeGroupDefinition(XMLSchemaComponent, AttributeGroupMarker, DefinitionMarker): """ parents: schema, redefine attributes: id -- ID name -- NCName, required contents: annotation?, (attribute | attributeGroup)*, anyAttribute? """ required = ['name'] attributes = {'id': None, 'name': None} contents = {'xsd': ['annotation', 'attribute', 'attributeGroup', 'anyAttribute']} tag = 'attributeGroup' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) elif component == 'attribute': if contents[indx].hasattr('name'): content.append(LocalAttributeDeclaration(self)) elif contents[indx].hasattr('ref'): content.append(AttributeReference(self)) else: raise SchemaError('Unknown attribute type') content[-1].fromDom(contents[indx]) elif component == 'attributeGroup': content.append(AttributeGroupReference(self)) content[-1].fromDom(contents[indx]) elif component == 'anyAttribute': if len(contents) != indx + 1: raise SchemaError( 'anyAttribute is out of order in %s' % self.getItemTrace()) content.append(AttributeWildCard(self)) content[-1].fromDom(contents[indx]) else: raise SchemaError('Unknown component (%s)' % (contents[indx].getTagName())) self.attr_content = tuple(content) class AttributeGroupReference(XMLSchemaComponent, AttributeGroupMarker, ReferenceMarker): """ parents: complexType, restriction, extension, attributeGroup attributes: id -- ID ref -- QName, required contents: annotation? """ required = ['ref'] attributes = {'id': None, 'ref': None} contents = {'xsd': ['annotation']} tag = 'attributeGroup' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getAttributeGroup(self, attribute='ref'): """attribute -- attribute with a QName value (eg. type). collection -- check types collection in parent Schema instance """ return XMLSchemaComponent.getAttributeGroup(self, attribute) def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) ###################################################### # Elements ##################################################### class IdentityConstrants(XMLSchemaComponent): """Allow one to uniquely identify nodes in a document and ensure the integrity of references between them. attributes -- dictionary of attributes selector -- XPath to selected nodes fields -- list of XPath to key field """ def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.selector = None self.fields = None self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) fields = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'selector': self.selector = self.Selector(self) self.selector.fromDom(i) continue elif component == 'field': fields.append(self.Field(self)) fields[-1].fromDom(i) continue else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.fields = tuple(fields) class Constraint(XMLSchemaComponent): def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError( 'Unknown component (%s)' % (i.getTagName())) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class Selector(Constraint): """ parent: unique, key, keyref attributes: id -- ID xpath -- XPath subset, required contents: annotation? """ required = ['xpath'] attributes = {'id': None, 'xpath': None} contents = {'xsd': ['annotation']} tag = 'selector' class Field(Constraint): """ parent: unique, key, keyref attributes: id -- ID xpath -- XPath subset, required contents: annotation? """ required = ['xpath'] attributes = {'id': None, 'xpath': None} contents = {'xsd': ['annotation']} tag = 'field' class Unique(IdentityConstrants): """ Enforce fields are unique w/i a specified scope. parent: element attributes: id -- ID name -- NCName, required contents: annotation?, selector, field+ """ required = ['name'] attributes = {'id': None, 'name': None} contents = {'xsd': ['annotation', 'selector', 'field']} tag = 'unique' class Key(IdentityConstrants): """ Enforce fields are unique w/i a specified scope, and all field values are present w/i document. Fields cannot be nillable. parent: element attributes: id -- ID name -- NCName, required contents: annotation?, selector, field+ """ required = ['name'] attributes = {'id': None, 'name': None} contents = {'xsd': ['annotation', 'selector', 'field']} tag = 'key' class KeyRef(IdentityConstrants): """ Ensure a match between two sets of values in an instance. parent: element attributes: id -- ID name -- NCName, required refer -- QName, required contents: annotation?, selector, field+ """ required = ['name', 'refer'] attributes = {'id': None, 'name': None, 'refer': None} contents = {'xsd': ['annotation', 'selector', 'field']} tag = 'keyref' class ElementDeclaration(XMLSchemaComponent, ElementMarker, DeclarationMarker): """ parents: schema attributes: id -- ID name -- NCName, required type -- QName default -- string fixed -- string nillable -- boolean, false abstract -- boolean, false substitutionGroup -- QName block -- ('#all' | ('substition' | 'extension' | 'restriction')*), schema.blockDefault final -- ('#all' | ('extension' | 'restriction')*), schema.finalDefault contents: annotation?, (simpleType,complexType)?, (key | keyref | unique)* """ required = ['name'] attributes = {'id': None, 'name': None, 'type': None, 'default': None, 'fixed': None, 'nillable': 0, 'abstract': 0, 'substitutionGroup': None, 'block': lambda self: self._parent().getBlockDefault(), 'final': lambda self: self._parent().getFinalDefault()} contents = {'xsd': ['annotation', 'simpleType', 'complexType', 'key', 'keyref', 'unique']} tag = 'element' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.constraints = () def isQualified(self): """Global elements are always qualified. """ return True def getAttribute(self, attribute): """return attribute. If attribute is type and it's None, and no simple or complex content, return the default type "xsd:anyType" """ value = XMLSchemaComponent.getAttribute(self, attribute) if attribute != 'type' or value is not None: return value if self.content is not None: return None parent = self while 1: nsdict = parent.attributes[XMLSchemaComponent.xmlns] for k, v in list(nsdict.items()): if v not in SCHEMA.XSD_LIST: continue return TypeDescriptionComponent((v, 'anyType')) if isinstance(parent, WSDLToolsAdapter)\ or not hasattr(parent, '_parent'): break parent = parent._parent() raise SchemaError('failed to locate the XSD namespace') def getElementDeclaration(self, attribute): raise Warning('invalid operation for <%s>' % self.tag) def getTypeDefinition(self, attribute=None): """If attribute is None, "type" is assumed, return the corresponding representation of the global type definition (TypeDefinition), or the local definition if don't find "type". To maintain backwards compat, if attribute is provided call base class method. """ if attribute: return XMLSchemaComponent.getTypeDefinition(self, attribute) gt = XMLSchemaComponent.getTypeDefinition(self, 'type') if gt: return gt return self.content def getConstraints(self): return self._constraints def setConstraints(self, constraints): self._constraints = tuple(constraints) constraints = property(getConstraints, setConstraints, None, "tuple of key, keyref, unique constraints") def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) constraints = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) elif component == 'simpleType' and not self.content: self.content = AnonymousSimpleType(self) self.content.fromDom(i) elif component == 'complexType' and not self.content: self.content = LocalComplexType(self) self.content.fromDom(i) elif component == 'key': constraints.append(Key(self)) constraints[-1].fromDom(i) elif component == 'keyref': constraints.append(KeyRef(self)) constraints[-1].fromDom(i) elif component == 'unique': constraints.append(Unique(self)) constraints[-1].fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.constraints = constraints class LocalElementDeclaration(ElementDeclaration, LocalMarker): """ parents: all, choice, sequence attributes: id -- ID name -- NCName, required form -- ('qualified' | 'unqualified'), schema.elementFormDefault type -- QName minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 default -- string fixed -- string nillable -- boolean, false block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault contents: annotation?, (simpleType,complexType)?, (key | keyref | unique)* """ required = ['name'] attributes = {'id': None, 'name': None, 'form': lambda self: GetSchema(self).getElementFormDefault(), 'type': None, 'minOccurs': '1', 'maxOccurs': '1', 'default': None, 'fixed': None, 'nillable': 0, 'abstract': 0, 'block': lambda self: GetSchema(self).getBlockDefault()} contents = {'xsd': ['annotation', 'simpleType', 'complexType', 'key', 'keyref', 'unique']} def isQualified(self): """ Local elements can be qualified or unqualifed according to the attribute form, or the elementFormDefault. By default local elements are unqualified. """ form = self.getAttribute('form') if form == 'qualified': return True if form == 'unqualified': return False raise SchemaError('Bad form (%s) for element: %s' % (form, self.getItemTrace())) class ElementReference(XMLSchemaComponent, ElementMarker, ReferenceMarker): """ parents: all, choice, sequence attributes: id -- ID ref -- QName, required minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation? """ required = ['ref'] attributes = {'id': None, 'ref': None, 'minOccurs': '1', 'maxOccurs': '1'} contents = {'xsd': ['annotation']} tag = 'element' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getElementDeclaration(self, attribute=None): """If attribute is None, "ref" is assumed, return the corresponding representation of the global element declaration (ElementDeclaration), To maintain backwards compat, if attribute is provided call base class method. """ if attribute: return XMLSchemaComponent.getElementDeclaration(self, attribute) return XMLSchemaComponent.getElementDeclaration(self, 'ref') def fromDom(self, node): self.annotation = None self.setAttributes(node) for i in self.getContents(node): component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class ElementWildCard(LocalElementDeclaration, WildCardMarker): """ parents: choice, sequence attributes: id -- ID minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 namespace -- '##any' | '##other' | (anyURI* | '##targetNamespace' | '##local'), ##any processContents -- 'lax' | 'skip' | 'strict', strict contents: annotation? """ required = [] attributes = {'id': None, 'minOccurs': '1', 'maxOccurs': '1', 'namespace': '##any', 'processContents': 'strict'} contents = {'xsd': ['annotation']} tag = 'any' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def isQualified(self): """ Global elements are always qualified, but if processContents are not strict could have dynamically generated local elements. """ return GetSchema(self).isElementFormDefaultQualified() def getAttribute(self, attribute): """return attribute. """ return XMLSchemaComponent.getAttribute(self, attribute) def getTypeDefinition(self, attribute): raise Warning('invalid operation for <%s>' % self.tag) def fromDom(self, node): self.annotation = None self.setAttributes(node) for i in self.getContents(node): component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) ###################################################### # Model Groups ##################################################### class Sequence(XMLSchemaComponent, SequenceMarker): """ parents: complexType, extension, restriction, group, choice, sequence attributes: id -- ID minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation?, (element | group | choice | sequence | any)* """ attributes = {'id': None, 'minOccurs': '1', 'maxOccurs': '1'} contents = {'xsd': ['annotation', 'element', 'group', 'choice', 'sequence', 'any']} tag = 'sequence' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'element': if i.hasattr('ref'): content.append(ElementReference(self)) else: content.append(LocalElementDeclaration(self)) elif component == 'group': content.append(ModelGroupReference(self)) elif component == 'choice': content.append(Choice(self)) elif component == 'sequence': content.append(Sequence(self)) elif component == 'any': content.append(ElementWildCard(self)) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) content[-1].fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.content = tuple(content) class All(XMLSchemaComponent, AllMarker): """ parents: complexType, extension, restriction, group attributes: id -- ID minOccurs -- '0' | '1', 1 maxOccurs -- '1', 1 contents: annotation?, element* """ attributes = {'id': None, 'minOccurs': '1', 'maxOccurs': '1'} contents = {'xsd': ['annotation', 'element']} tag = 'all' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'element': if i.hasattr('ref'): content.append(ElementReference(self)) else: content.append(LocalElementDeclaration(self)) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) content[-1].fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.content = tuple(content) class Choice(XMLSchemaComponent, ChoiceMarker): """ parents: complexType, extension, restriction, group, choice, sequence attributes: id -- ID minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation?, (element | group | choice | sequence | any)* """ attributes = {'id': None, 'minOccurs': '1', 'maxOccurs': '1'} contents = {'xsd': ['annotation', 'element', 'group', 'choice', 'sequence', 'any']} tag = 'choice' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'element': if i.hasattr('ref'): content.append(ElementReference(self)) else: content.append(LocalElementDeclaration(self)) elif component == 'group': content.append(ModelGroupReference(self)) elif component == 'choice': content.append(Choice(self)) elif component == 'sequence': content.append(Sequence(self)) elif component == 'any': content.append(ElementWildCard(self)) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) content[-1].fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.content = tuple(content) class ModelGroupDefinition(XMLSchemaComponent, ModelGroupMarker, DefinitionMarker): """ parents: redefine, schema attributes: id -- ID name -- NCName, required contents: annotation?, (all | choice | sequence)? """ required = ['name'] attributes = {'id': None, 'name': None} contents = {'xsd': ['annotation', 'all', 'choice', 'sequence']} tag = 'group' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'all' and not self.content: self.content = All(self) elif component == 'choice' and not self.content: self.content = Choice(self) elif component == 'sequence' and not self.content: self.content = Sequence(self) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.content.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class ModelGroupReference(XMLSchemaComponent, ModelGroupMarker, ReferenceMarker): """ parents: choice, complexType, extension, restriction, sequence attributes: id -- ID ref -- NCName, required minOccurs -- Whole Number, 1 maxOccurs -- (Whole Number | 'unbounded'), 1 contents: annotation? """ required = ['ref'] attributes = {'id': None, 'ref': None, 'minOccurs': '1', 'maxOccurs': '1'} contents = {'xsd': ['annotation']} tag = 'group' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None def getModelGroupReference(self): return self.getModelGroup('ref') def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) class ComplexType(XMLSchemaComponent, DefinitionMarker, ComplexMarker): """ parents: redefine, schema attributes: id -- ID name -- NCName, required mixed -- boolean, false abstract -- boolean, false block -- ('#all' | ('extension' | 'restriction')*), schema.blockDefault final -- ('#all' | ('extension' | 'restriction')*), schema.finalDefault contents: annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?)) """ required = ['name'] attributes = {'id': None, 'name': None, 'mixed': 0, 'abstract': 0, 'block': lambda self: self._parent().getBlockDefault(), 'final': lambda self: self._parent().getFinalDefault()} contents = {'xsd': ['annotation', 'simpleContent', 'complexContent', 'group', 'all', 'choice', 'sequence', 'attribute', 'attributeGroup', 'anyAttribute', 'any']} tag = 'complexType' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.attr_content = None def isMixed(self): m = self.getAttribute('mixed') if not m: return False if isinstance(m, string_types): if m in ('false', '0'): return False if m in ('true', '1'): return True raise SchemaError( 'invalid value for attribute mixed(%s): %s' % (m, self.getItemTrace())) def getAttributeContent(self): return self.attr_content def getElementDeclaration(self, attribute): raise Warning('invalid operation for <%s>' % self.tag) def getTypeDefinition(self, attribute): raise Warning('invalid operation for <%s>' % self.tag) def fromDom(self, node): self.setAttributes(node) contents = list(self.getContents(node)) indx = 0 num = len(contents) if not num: return component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 if indx < num: component = SplitQName(contents[indx].getTagName())[1] self.content = None if component == 'simpleContent': self.content = self.__class__.SimpleContent(self) self.content.fromDom(contents[indx]) elif component == 'complexContent': self.content = self.__class__.ComplexContent(self) self.content.fromDom(contents[indx]) else: if component == 'all': self.content = All(self) elif component == 'choice': self.content = Choice(self) elif component == 'sequence': self.content = Sequence(self) elif component == 'group': self.content = ModelGroupReference(self) if self.content: self.content.fromDom(contents[indx]) indx += 1 self.attr_content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): self.attr_content.append(AttributeReference(self)) else: self.attr_content.append( LocalAttributeDeclaration(self)) elif component == 'attributeGroup': self.attr_content.append(AttributeGroupReference(self)) elif component == 'anyAttribute': self.attr_content.append(AttributeWildCard(self)) else: raise SchemaError('Unknown component (%s): %s' % ( contents[indx].getTagName(), self.getItemTrace())) self.attr_content[-1].fromDom(contents[indx]) indx += 1 class _DerivedType(XMLSchemaComponent): def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None # XXX remove attribute derivation, inconsistent self.derivation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for i in contents: component = SplitQName(i.getTagName())[1] if component in self.__class__.contents['xsd']: if component == 'annotation' and not self.annotation: self.annotation = Annotation(self) self.annotation.fromDom(i) continue elif component == 'restriction' and not self.derivation: self.derivation = self.__class__.Restriction(self) elif component == 'extension' and not self.derivation: self.derivation = self.__class__.Extension(self) else: raise SchemaError( 'Unknown component (%s)' % (i.getTagName())) else: raise SchemaError('Unknown component (%s)' % (i.getTagName())) self.derivation.fromDom(i) self.content = self.derivation class ComplexContent(_DerivedType, ComplexMarker): """ parents: complexType attributes: id -- ID mixed -- boolean, false contents: annotation?, (restriction | extension) """ attributes = {'id': None, 'mixed': 0} contents = {'xsd': ['annotation', 'restriction', 'extension']} tag = 'complexContent' def isMixed(self): m = self.getAttribute('mixed') if not m: return False if isinstance(m, string_types) is True: if m in ('false', '0'): return False if m in ('true', '1'): return True raise SchemaError( 'invalid value for attribute mixed(%s): %s' % (m, self.getItemTrace())) class _DerivationBase(XMLSchemaComponent): """, parents: complexContent attributes: id -- ID base -- QName, required contents: annotation?, (group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute? """ required = ['base'] attributes = {'id': None, 'base': None} contents = {'xsd': ['annotation', 'group', 'all', 'choice', 'sequence', 'attribute', 'attributeGroup', 'anyAttribute']} def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) indx = 0 num = len(contents) # XXX ugly if not num: return component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 component = SplitQName(contents[indx].getTagName())[1] if component == 'all': self.content = All(self) self.content.fromDom(contents[indx]) indx += 1 elif component == 'choice': self.content = Choice(self) self.content.fromDom(contents[indx]) indx += 1 elif component == 'sequence': self.content = Sequence(self) self.content.fromDom(contents[indx]) indx += 1 elif component == 'group': self.content = ModelGroupReference(self) self.content.fromDom(contents[indx]) indx += 1 else: self.content = None self.attr_content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): self.attr_content.append(AttributeReference(self)) else: self.attr_content.append( LocalAttributeDeclaration(self)) elif component == 'attributeGroup': if contents[indx].hasattr('ref'): self.attr_content.append( AttributeGroupReference(self)) else: self.attr_content.append( AttributeGroupDefinition(self)) elif component == 'anyAttribute': self.attr_content.append(AttributeWildCard(self)) else: raise SchemaError('Unknown component (%s)' % (contents[indx].getTagName())) self.attr_content[-1].fromDom(contents[indx]) indx += 1 class Extension(_DerivationBase, ExtensionMarker): """ parents: complexContent attributes: id -- ID base -- QName, required contents: annotation?, (group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute? """ tag = 'extension' class Restriction(_DerivationBase, RestrictionMarker): """ parents: complexContent attributes: id -- ID base -- QName, required contents: annotation?, (group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute? """ tag = 'restriction' class SimpleContent(_DerivedType, SimpleMarker): """ parents: complexType attributes: id -- ID contents: annotation?, (restriction | extension) """ attributes = {'id': None} contents = {'xsd': ['annotation', 'restriction', 'extension']} tag = 'simpleContent' class Extension(XMLSchemaComponent, ExtensionMarker): """ parents: simpleContent attributes: id -- ID base -- QName, required contents: annotation?, (attribute | attributeGroup)*, anyAttribute? """ required = ['base'] attributes = {'id': None, 'base': None} contents = {'xsd': ['annotation', 'attribute', 'attributeGroup', 'anyAttribute']} tag = 'extension' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) indx = 0 num = len(contents) if num: component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 component = SplitQName(contents[indx].getTagName())[1] content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): content.append(AttributeReference(self)) else: content.append(LocalAttributeDeclaration(self)) elif component == 'attributeGroup': content.append(AttributeGroupReference(self)) elif component == 'anyAttribute': content.append(AttributeWildCard(self)) else: raise SchemaError('Unknown component (%s)' % (contents[indx].getTagName())) content[-1].fromDom(contents[indx]) indx += 1 self.attr_content = tuple(content) class Restriction(XMLSchemaComponent, RestrictionMarker): """ parents: simpleContent attributes: id -- ID base -- QName, required contents: annotation?, simpleType?, (enumeration | length | maxExclusive | maxInclusive | maxLength | minExclusive | minInclusive | minLength | pattern | fractionDigits | totalDigits | whiteSpace)*, (attribute | attributeGroup)*, anyAttribute? """ required = ['base'] attributes = {'id': None, 'base': None} contents = {'xsd': ['annotation', 'simpleType', 'attribute', 'attributeGroup', 'anyAttribute'] + RestrictionMarker.facets} tag = 'restriction' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.attr_content = None def getAttributeContent(self): return self.attr_content def fromDom(self, node): self.content = [] self.setAttributes(node) contents = self.getContents(node) indx = 0 num = len(contents) component = SplitQName(contents[indx].getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) indx += 1 component = SplitQName(contents[indx].getTagName())[1] content = [] while indx < num: component = SplitQName(contents[indx].getTagName())[1] if component == 'attribute': if contents[indx].hasattr('ref'): content.append(AttributeReference(self)) else: content.append(LocalAttributeDeclaration(self)) elif component == 'attributeGroup': content.append(AttributeGroupReference(self)) elif component == 'anyAttribute': content.append(AttributeWildCard(self)) elif component == 'simpleType': self.content.append(AnonymousSimpleType(self)) self.content[-1].fromDom(contents[indx]) else: raise SchemaError('Unknown component (%s)' % (contents[indx].getTagName())) content[-1].fromDom(contents[indx]) indx += 1 self.attr_content = tuple(content) class LocalComplexType(ComplexType, LocalMarker): """ parents: element attributes: id -- ID mixed -- boolean, false contents: annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, (attribute | attributeGroup)*, anyAttribute?)) """ required = [] attributes = {'id': None, 'mixed': 0} tag = 'complexType' class SimpleType(XMLSchemaComponent, DefinitionMarker, SimpleMarker): """ parents: redefine, schema attributes: id -- ID name -- NCName, required final -- ('#all' | ('extension' | 'restriction' | 'list' | 'union')*), schema.finalDefault contents: annotation?, (restriction | list | union) """ required = ['name'] attributes = {'id': None, 'name': None, 'final': lambda self: self._parent().getFinalDefault()} contents = {'xsd': ['annotation', 'restriction', 'list', 'union']} tag = 'simpleType' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def getElementDeclaration(self, attribute): raise Warning('invalid operation for <%s>' % self.tag) def getTypeDefinition(self, attribute): raise Warning('invalid operation for <%s>' % self.tag) def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) for child in contents: component = SplitQName(child.getTagName())[1] if component == 'annotation': self.annotation = Annotation(self) self.annotation.fromDom(child) continue break else: return if component == 'restriction': self.content = self.__class__.Restriction(self) elif component == 'list': self.content = self.__class__.List(self) elif component == 'union': self.content = self.__class__.Union(self) else: raise SchemaError('Unknown component (%s)' % (component)) self.content.fromDom(child) class Restriction(XMLSchemaComponent, RestrictionMarker): """ parents: simpleType attributes: id -- ID base -- QName, required or simpleType child contents: annotation?, simpleType?, (enumeration | length | maxExclusive | maxInclusive | maxLength | minExclusive | minInclusive | minLength | pattern | fractionDigits | totalDigits | whiteSpace)* """ attributes = {'id': None, 'base': None} contents = {'xsd': ['annotation', 'simpleType'] + RestrictionMarker.facets} tag = 'restriction' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None self.facets = None def getAttributeBase(self): return XMLSchemaComponent.getAttribute(self, 'base') def getTypeDefinition(self, attribute='base'): return XMLSchemaComponent.getTypeDefinition(self, attribute) def getSimpleTypeContent(self): for el in self.content: if el.isSimple(): return el return None def fromDom(self, node): self.facets = [] self.setAttributes(node) contents = self.getContents(node) content = [] for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) continue elif (component == 'simpleType') and (not indx or indx == 1): content.append(AnonymousSimpleType(self)) content[-1].fromDom(contents[indx]) elif component in RestrictionMarker.facets: self.facets.append(contents[indx]) else: raise SchemaError('Unknown component (%s)' % (contents[indx].getTagName())) self.content = tuple(content) class Union(XMLSchemaComponent, UnionMarker): """ parents: simpleType attributes: id -- ID memberTypes -- list of QNames, required or simpleType child. contents: annotation?, simpleType* """ attributes = {'id': None, 'memberTypes': None} contents = {'xsd': ['annotation', 'simpleType']} tag = 'union' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def fromDom(self, node): self.setAttributes(node) contents = self.getContents(node) content = [] for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) elif (component == 'simpleType'): content.append(AnonymousSimpleType(self)) content[-1].fromDom(contents[indx]) else: raise SchemaError('Unknown component (%s)' % (contents[indx].getTagName())) self.content = tuple(content) class List(XMLSchemaComponent, ListMarker): """ parents: simpleType attributes: id -- ID itemType -- QName, required or simpleType child. contents: annotation?, simpleType? """ attributes = {'id': None, 'itemType': None} contents = {'xsd': ['annotation', 'simpleType']} tag = 'list' def __init__(self, parent): XMLSchemaComponent.__init__(self, parent) self.annotation = None self.content = None def getItemType(self): return self.attributes.get('itemType') def getTypeDefinition(self, attribute='itemType'): """ return the type refered to by itemType attribute or the simpleType content. If returns None, then the type refered to by itemType is primitive. """ tp = XMLSchemaComponent.getTypeDefinition(self, attribute) return tp or self.content def fromDom(self, node): self.annotation = None self.content = None self.setAttributes(node) contents = self.getContents(node) for indx in range(len(contents)): component = SplitQName(contents[indx].getTagName())[1] if (component == 'annotation') and (not indx): self.annotation = Annotation(self) self.annotation.fromDom(contents[indx]) elif (component == 'simpleType'): self.content = AnonymousSimpleType(self) self.content.fromDom(contents[indx]) break else: raise SchemaError('Unknown component (%s)' % (contents[indx].getTagName())) class AnonymousSimpleType(SimpleType, SimpleMarker, LocalMarker): """ parents: attribute, element, list, restriction, union attributes: id -- ID contents: annotation?, (restriction | list | union) """ required = [] attributes = {'id': None} tag = 'simpleType' class Redefine: """ parents: attributes: contents: """ tag = 'redefine' ########################### ########################### if sys.version_info[:2] >= (2, 2): tupleClass = tuple else: from . import UserTuple tupleClass = UserTuple.UserTuple class TypeDescriptionComponent(tupleClass): """Tuple of length 2, consisting of a namespace and unprefixed name. """ def __new__(typ, args): """args -- (namespace, name) Remove the name's prefix, irrelevant. """ if len(args) != 2: raise TypeError('expecting tuple (namespace, name), got %s' % args) elif args[1].find(':') >= 0: args = (args[0], SplitQName(args[1])[1]) return tuple.__new__(typ, args) def getTargetNamespace(self): return self[0] def getName(self): return self[1]