--- /dev/null
+# 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 types, weakref, sys, warnings
+from Namespaces import SCHEMA, XMLNS, SOAP, APACHE
+from Utility import DOM, DOMException, Collection, SplitQName, basejoin
+from StringIO import StringIO
+
+# If we have no threading, this should be a no-op
+try:
+ from threading import RLock
+except ImportError:
+ class RLock:
+ 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:
+ """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 schema.imports.items():
+ if self._imports.has_key(ns):
+ schema.addImportSchema(self._imports[ns])
+
+ def __setIncludes(self, schema):
+ """Add dictionary of includes to schema instance.
+ schema -- XMLSchema instance
+ """
+ for schemaLocation, val in schema.includes.items():
+ if self._includes.has_key(schemaLocation):
+ 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:
+ 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 self.__attributes.get(ns,{}).has_key(attr)
+ return self.__attributes.has_key(attr)
+
+ 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 map(self.__class__, nodes)
+
+ def setAttributeDictionary(self):
+ self.__attributes = {}
+ for v in 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, ex:
+ 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 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 (type(self.__class__.required) == type(XMLSchemaComponent.required)\
+ and type(self.__class__.attributes) == type(XMLSchemaComponent.attributes)\
+ and type(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 <schema> 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, ex:
+ raise KeyError, 'targetNamespace(%s) collection(%s) has no item(%s)'\
+ %(namespace, collection, name)
+
+ return obj
+
+ if not parent.imports.has_key(namespace):
+ 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, ex:
+ 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 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 not self.attributes.has_key(ns):
+ self.attributes[ns] = {}
+ elif self.attributes[ns].has_key(value):
+ raise SchemaError, 'attribute %s declared multiple times in %s'\
+ %(value, ns)
+ self.attributes[ns][value] = v
+ elif not self.attributes.has_key(value):
+ 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 self.attributes.has_key(k):
+ 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 self.attributes.has_key(k):
+ 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 self.__class__.attributes.items():
+ if v is not None and self.attributes.has_key(k) 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 not self.attributes.has_key(a):
+ raise SchemaError,\
+ 'class instance %s, missing required attribute %s'\
+ %(self.__class__, a)
+ for a,v in 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 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):
+ """<notation>
+ 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):
+ """<annotation>
+ 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):
+ """<documentation>
+ 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):
+ """<appinfo>
+ 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 <schema> element
+ information items. It represents the abstract notion of a schema
+ rather than a single schema document (or other representation).
+
+ <schema>
+ 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):
+ """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
+
+ 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 attributes['xmlns'].items():
+ if not self.attributes['xmlns'].has_key(k):
+ 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 not self.getIncludeSchemas().has_key(sl):
+ 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 getattr(schema,collection).items():
+ if not getattr(self,collection).has_key(k):
+ 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, ex:
+ # Dependency declaration, hopefully implementation
+ # is aware of this namespace (eg. SOAP,WSDL,?)
+ print "IMPORT: ", import_ns
+ print ex
+ del slocd[import_ns]
+ continue
+ except SchemaError, ex:
+ #warnings.warn(\
+ # '<import namespace="%s" schemaLocation=?>, %s'\
+ # %(import_ns, 'failed to load schema instance')
+ #)
+ print 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 self.getImportSchemas().has_key(import_ns):
+ 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):
+ """<import>
+ 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 not self.attributes.has_key('schemaLocation'):
+ raise NoSchemaLocationWarning('no schemaLocation attribute in import')
+
+ reader.loadFromURL(self.attributes.get('schemaLocation'), schema)
+
+
+ class Include(XMLSchemaComponent):
+ """<include schemaLocation>
+ 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):
+ """<attribute name>
+ 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):
+ """<attribute name>
+ 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):
+ """<anyAttribute>
+ 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):
+ """<attribute ref>
+ 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):
+ """<attributeGroup name>
+ 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):
+ """<attributeGroup ref>
+ 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):
+ """<selector xpath>
+ 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):
+ """<field xpath>
+ 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):
+ """<unique name> 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):
+ """<key name> 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):
+ """<keyref name refer> 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):
+ """<element name>
+ 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 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):
+ """<element>
+ 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):
+ """<element ref>
+ 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):
+ """<any>
+ 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):
+ """<sequence>
+ 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):
+ """<all>
+ 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):
+ """<choice>
+ 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):
+ """<group name>
+ 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):
+ """<group ref>
+ 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):
+ """<complexType name>
+ 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 m == 0 or m == False:
+ return False
+ if isinstance(m, basestring) 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())
+
+ 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 = 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):
+ """<complexContent>
+ 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 m == 0 or m == False:
+ return False
+ if isinstance(m, basestring) 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):
+ """<extension>,<restriction>
+ 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):
+ """<extension base>
+ parents:
+ complexContent
+ attributes:
+ id -- ID
+ base -- QName, required
+
+ contents:
+ annotation?, (group | all | choice | sequence)?,
+ (attribute | attributeGroup)*, anyAttribute?
+ """
+ tag = 'extension'
+
+ class Restriction(_DerivationBase,\
+ RestrictionMarker):
+ """<restriction base>
+ parents:
+ complexContent
+ attributes:
+ id -- ID
+ base -- QName, required
+
+ contents:
+ annotation?, (group | all | choice | sequence)?,
+ (attribute | attributeGroup)*, anyAttribute?
+ """
+ tag = 'restriction'
+
+
+ class SimpleContent(_DerivedType,\
+ SimpleMarker):
+ """<simpleContent>
+ parents:
+ complexType
+ attributes:
+ id -- ID
+
+ contents:
+ annotation?, (restriction | extension)
+ """
+ attributes = {'id':None}
+ contents = {'xsd':['annotation', 'restriction', 'extension']}
+ tag = 'simpleContent'
+
+ class Extension(XMLSchemaComponent,\
+ ExtensionMarker):
+ """<extension base>
+ 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):
+ """<restriction base>
+ 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):
+ """<complexType>
+ 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):
+ """<simpleType name>
+ 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):
+ """<restriction base>
+ 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)' %(i.getTagName())
+ self.content = tuple(content)
+
+
+ class Union(XMLSchemaComponent,
+ UnionMarker):
+ """<union>
+ 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)' %(i.getTagName())
+ self.content = tuple(content)
+
+ class List(XMLSchemaComponent,
+ ListMarker):
+ """<list>
+ 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)' %(i.getTagName())
+
+
+class AnonymousSimpleType(SimpleType,\
+ SimpleMarker,\
+ LocalMarker):
+ """<simpleType>
+ parents:
+ attribute, element, list, restriction, union
+ attributes:
+ id -- ID
+
+ contents:
+ annotation?, (restriction | list | union)
+ """
+ required = []
+ attributes = {'id':None}
+ tag = 'simpleType'
+
+
+class Redefine:
+ """<redefine>
+ parents:
+ attributes:
+
+ contents:
+ """
+ tag = 'redefine'
+
+
+###########################
+###########################
+
+
+if sys.version_info[:2] >= (2, 2):
+ tupleClass = tuple
+else:
+ import UserTuple
+ tupleClass = UserTuple.UserTuple
+
+class TypeDescriptionComponent(tupleClass):
+ """Tuple of length 2, consisting of
+ a namespace and unprefixed name.
+ """
+ def __init__(self, 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])
+ tuple.__init__(self, args)
+ return
+
+ def getTargetNamespace(self):
+ return self[0]
+
+ def getName(self):
+ return self[1]
+
+