bundled wstools-0.3
[p2pool.git] / wstools / XMLSchema.py
diff --git a/wstools/XMLSchema.py b/wstools/XMLSchema.py
new file mode 100755 (executable)
index 0000000..eb5b3fe
--- /dev/null
@@ -0,0 +1,3116 @@
+# 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]
+
+