def __init__(self, targetNamespace=None, strict=1): self.targetNamespace = targetNamespace or 'urn:this-document.wsdl' self.documentation = '' self.location = None self.document = None self.name = None self.services = CollectionNS(self) self.messages = CollectionNS(self) self.portTypes = CollectionNS(self) self.bindings = CollectionNS(self) #self.imports = Collection(self) self.types = Types(self) self.extensions = [] self.strict = strict
class WSDL: """A WSDL object models a WSDL service description. WSDL objects may be created manually or loaded from an xml representation using a WSDLReader instance.""" def __init__(self, targetNamespace=None, strict=1): self.targetNamespace = targetNamespace or 'urn:this-document.wsdl' self.documentation = '' self.location = None self.document = None self.name = None self.services = CollectionNS(self) self.messages = CollectionNS(self) self.portTypes = CollectionNS(self) self.bindings = CollectionNS(self) #self.imports = Collection(self) self.types = Types(self) self.extensions = [] self.strict = strict def __del__(self): if self.document is not None: self.document.unlink() version = '1.1' def addService(self, name, documentation='', targetNamespace=None): if self.services.has_key(name): raise WSDLError( 'Duplicate service element: %s' % name ) item = Service(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.services[name] = item return item def addMessage(self, name, documentation='', targetNamespace=None): if self.messages.has_key(name): raise WSDLError( 'Duplicate message element: %s.' % name ) item = Message(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.messages[name] = item return item def addPortType(self, name, documentation='', targetNamespace=None): if self.portTypes.has_key(name): raise WSDLError( 'Duplicate portType element: name' ) item = PortType(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.portTypes[name] = item return item def addBinding(self, name, type, documentation='', targetNamespace=None): if self.bindings.has_key(name): raise WSDLError( 'Duplicate binding element: %s' % name ) item = Binding(name, type, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.bindings[name] = item return item #def addImport(self, namespace, location): # item = ImportElement(namespace, location) # self.imports[namespace] = item # return item def load(self, document): # We save a reference to the DOM document to ensure that elements # saved as "extensions" will continue to have a meaningful context # for things like namespace references. The lifetime of the DOM # document is bound to the lifetime of the WSDL instance. self.document = document definitions = DOM.getElement(document, 'definitions', None, None) if definitions is None: raise WSDLError( 'Missing <definitions> element.' ) self.version = DOM.WSDLUriToVersion(definitions.namespaceURI) NS_WSDL = DOM.GetWSDLUri(self.version) self.targetNamespace = DOM.getAttr(definitions, 'targetNamespace', None, None) self.name = DOM.getAttr(definitions, 'name', None, None) self.documentation = GetDocumentation(definitions) # Resolve (recursively) any import elements in the document. imported = {} base_location = self.location while 1: #XXX imports = [] for element in DOM.getElements(definitions, 'import', NS_WSDL): location = DOM.getAttr(element, 'location') # Resolve relative location, and save location = urllib.basejoin(base_location, location) if not imported.has_key(location): imports.append(element) if not imports: break for element in imports: location = DOM.getAttr(element, 'location') self._import(document, element, base_location) location = urllib.basejoin(base_location, location) imported[location] = 1 base_location = '' #reader = SchemaReader(base_url=self.location) for element in DOM.getElements(definitions, None, None): targetNamespace = DOM.getAttr(element, 'targetNamespace') localName = element.localName if not DOM.nsUriMatch(element.namespaceURI, NS_WSDL): if localName == 'schema': reader = SchemaReader(base_url=self.location) schema = reader.loadFromNode(WSDLToolsAdapter(self), element) schema.setBaseUrl(self.location) self.types.addSchema(schema) else: self.extensions.append(element) continue elif localName == 'message': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) message = self.addMessage(name, docs, targetNamespace) parts = DOM.getElements(element, 'part', NS_WSDL) message.load(parts) continue elif localName == 'portType': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) ptype = self.addPortType(name, docs, targetNamespace) #operations = DOM.getElements(element, 'operation', NS_WSDL) #ptype.load(operations) ptype.load(element) continue elif localName == 'binding': name = DOM.getAttr(element, 'name') type = DOM.getAttr(element, 'type', default=None) if type is None: raise WSDLError( 'Missing type attribute for binding %s.' % name ) type = ParseQName(type, element) docs = GetDocumentation(element) binding = self.addBinding(name, type, docs, targetNamespace) operations = DOM.getElements(element, 'operation', NS_WSDL) binding.load(operations) binding.load_ex(GetExtensions(element)) continue elif localName == 'service': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) service = self.addService(name, docs, targetNamespace) ports = DOM.getElements(element, 'port', NS_WSDL) service.load(ports) service.load_ex(GetExtensions(element)) continue elif localName == 'types': self.types.documentation = GetDocumentation(element) base_location = DOM.getAttr(element, 'base-location') if base_location: element.removeAttribute('base-location') base_location = base_location or self.location reader = SchemaReader(base_url=base_location) for item in DOM.getElements(element, None, None): if item.localName == 'schema': schema = reader.loadFromNode(WSDLToolsAdapter(self), item) # XXX <types> could have been imported #schema.setBaseUrl(self.location) schema.setBaseUrl(base_location) self.types.addSchema(schema) else: self.types.addExtension(item) # XXX remove the attribute # element.removeAttribute('base-location') continue def _import(self, document, element, base_location=None): '''Algo take <import> element's children, clone them, and add them to the main document. Support for relative locations is a bit complicated. The orig document context is lost, so we need to store base location in DOM elements representing <types>, by creating a special temporary "base-location" attribute, and <import>, by resolving the relative "location" and storing it as "location". document -- document we are loading element -- DOM Element representing <import> base_location -- location of document from which this <import> was gleaned. ''' namespace = DOM.getAttr(element, 'namespace', default=None) location = DOM.getAttr(element, 'location', default=None) if namespace is None or location is None: raise WSDLError( 'Invalid import element (missing namespace or location).' ) if base_location: location = urllib.basejoin(base_location, location) element.setAttributeNS(None, 'location', location) #location = urllib.basejoin(self.location, location) #obimport = self.addImport(namespace, location) #obimport._loaded = 1 importdoc = DOM.loadFromURL(location) try: if location.find('#') > -1: idref = location.split('#')[-1] imported = DOM.getElementById(importdoc, idref) else: imported = importdoc.documentElement if imported is None: raise WSDLError( 'Import target element not found for: %s' % location ) imported_tns = DOM.findTargetNS(imported) if imported_tns != namespace: return if imported.localName == 'definitions': imported_nodes = imported.childNodes else: imported_nodes = [imported] parent = element.parentNode for node in imported_nodes: if node.nodeType != node.ELEMENT_NODE: continue child = DOM.importNode(document, node, 1) parent.appendChild(child) child.setAttribute('targetNamespace', namespace) attrsNS = imported._attrsNS for attrkey in attrsNS.keys(): if attrkey[0] == DOM.NS_XMLNS: attr = attrsNS[attrkey].cloneNode(1) child.setAttributeNode(attr) #XXX Quick Hack, should be in WSDL Namespace. if child.localName == 'import': rlocation = child.getAttributeNS(None, 'location') alocation = urllib.basejoin(location, rlocation) child.setAttribute('location', alocation) elif child.localName == 'types': child.setAttribute('base-location', location) finally: importdoc.unlink() return location
class WSDL: """A WSDL object models a WSDL service description. WSDL objects may be created manually or loaded from an xml representation using a WSDLReader instance.""" def __init__(self, targetNamespace=None, strict=1): self.targetNamespace = targetNamespace or 'urn:this-document.wsdl' self.documentation = '' self.location = None self.document = None self.name = None self.services = CollectionNS(self) self.messages = CollectionNS(self) self.portTypes = CollectionNS(self) self.bindings = CollectionNS(self) #self.imports = Collection(self) self.types = Types(self) self.extensions = [] self.strict = strict def __del__(self): if self.document is not None: self.document.unlink() version = '1.1' def addService(self, name, documentation='', targetNamespace=None): if self.services.has_key(name): raise WSDLError('Duplicate service element: %s' % name) item = Service(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.services[name] = item return item def addMessage(self, name, documentation='', targetNamespace=None): if self.messages.has_key(name): raise WSDLError('Duplicate message element: %s.' % name) item = Message(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.messages[name] = item return item def addPortType(self, name, documentation='', targetNamespace=None): if self.portTypes.has_key(name): raise WSDLError('Duplicate portType element: name') item = PortType(name, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.portTypes[name] = item return item def addBinding(self, name, type, documentation='', targetNamespace=None): if self.bindings.has_key(name): raise WSDLError('Duplicate binding element: %s' % name) item = Binding(name, type, documentation) if targetNamespace: item.targetNamespace = targetNamespace self.bindings[name] = item return item #def addImport(self, namespace, location): # item = ImportElement(namespace, location) # self.imports[namespace] = item # return item def load(self, document): # We save a reference to the DOM document to ensure that elements # saved as "extensions" will continue to have a meaningful context # for things like namespace references. The lifetime of the DOM # document is bound to the lifetime of the WSDL instance. self.document = document definitions = DOM.getElement(document, 'definitions', None, None) if definitions is None: raise WSDLError('Missing <definitions> element.') self.version = DOM.WSDLUriToVersion(definitions.namespaceURI) NS_WSDL = DOM.GetWSDLUri(self.version) self.targetNamespace = DOM.getAttr(definitions, 'targetNamespace', None, None) self.name = DOM.getAttr(definitions, 'name', None, None) self.documentation = GetDocumentation(definitions) # Resolve (recursively) any import elements in the document. imported = {} base_location = self.location while 1: #XXX imports = [] for element in DOM.getElements(definitions, 'import', NS_WSDL): location = DOM.getAttr(element, 'location') # Resolve relative location, and save location = urllib.basejoin(base_location, location) if not imported.has_key(location): imports.append(element) if not imports: break for element in imports: location = DOM.getAttr(element, 'location') self._import(document, element, base_location) location = urllib.basejoin(base_location, location) imported[location] = 1 base_location = '' #reader = SchemaReader(base_url=self.location) for element in DOM.getElements(definitions, None, None): targetNamespace = DOM.getAttr(element, 'targetNamespace') localName = element.localName if not DOM.nsUriMatch(element.namespaceURI, NS_WSDL): if localName == 'schema': reader = SchemaReader(base_url=self.location) schema = reader.loadFromNode(WSDLToolsAdapter(self), element) schema.setBaseUrl(self.location) self.types.addSchema(schema) else: self.extensions.append(element) continue elif localName == 'message': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) message = self.addMessage(name, docs, targetNamespace) parts = DOM.getElements(element, 'part', NS_WSDL) message.load(parts) continue elif localName == 'portType': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) ptype = self.addPortType(name, docs, targetNamespace) #operations = DOM.getElements(element, 'operation', NS_WSDL) #ptype.load(operations) ptype.load(element) continue elif localName == 'binding': name = DOM.getAttr(element, 'name') type = DOM.getAttr(element, 'type', default=None) if type is None: raise WSDLError('Missing type attribute for binding %s.' % name) type = ParseQName(type, element) docs = GetDocumentation(element) binding = self.addBinding(name, type, docs, targetNamespace) operations = DOM.getElements(element, 'operation', NS_WSDL) binding.load(operations) binding.load_ex(GetExtensions(element)) continue elif localName == 'service': name = DOM.getAttr(element, 'name') docs = GetDocumentation(element) service = self.addService(name, docs, targetNamespace) ports = DOM.getElements(element, 'port', NS_WSDL) service.load(ports) service.load_ex(GetExtensions(element)) continue elif localName == 'types': self.types.documentation = GetDocumentation(element) base_location = DOM.getAttr(element, 'base-location') if base_location: element.removeAttribute('base-location') base_location = base_location or self.location reader = SchemaReader(base_url=base_location) for item in DOM.getElements(element, None, None): if item.localName == 'schema': schema = reader.loadFromNode(WSDLToolsAdapter(self), item) # XXX <types> could have been imported #schema.setBaseUrl(self.location) schema.setBaseUrl(base_location) self.types.addSchema(schema) else: self.types.addExtension(item) # XXX remove the attribute # element.removeAttribute('base-location') continue def _import(self, document, element, base_location=None): '''Algo take <import> element's children, clone them, and add them to the main document. Support for relative locations is a bit complicated. The orig document context is lost, so we need to store base location in DOM elements representing <types>, by creating a special temporary "base-location" attribute, and <import>, by resolving the relative "location" and storing it as "location". document -- document we are loading element -- DOM Element representing <import> base_location -- location of document from which this <import> was gleaned. ''' namespace = DOM.getAttr(element, 'namespace', default=None) location = DOM.getAttr(element, 'location', default=None) if namespace is None or location is None: raise WSDLError( 'Invalid import element (missing namespace or location).') if base_location: location = urllib.basejoin(base_location, location) element.setAttributeNS(None, 'location', location) #location = urllib.basejoin(self.location, location) #obimport = self.addImport(namespace, location) #obimport._loaded = 1 importdoc = DOM.loadFromURL(location) try: if location.find('#') > -1: idref = location.split('#')[-1] imported = DOM.getElementById(importdoc, idref) else: imported = importdoc.documentElement if imported is None: raise WSDLError('Import target element not found for: %s' % location) imported_tns = DOM.findTargetNS(imported) if imported_tns != namespace: return if imported.localName == 'definitions': imported_nodes = imported.childNodes else: imported_nodes = [imported] parent = element.parentNode for node in imported_nodes: if node.nodeType != node.ELEMENT_NODE: continue child = DOM.importNode(document, node, 1) parent.appendChild(child) child.setAttribute('targetNamespace', namespace) attrsNS = imported._attrsNS for attrkey in attrsNS.keys(): if attrkey[0] == DOM.NS_XMLNS: attr = attrsNS[attrkey].cloneNode(1) child.setAttributeNode(attr) #XXX Quick Hack, should be in WSDL Namespace. if child.localName == 'import': rlocation = child.getAttributeNS(None, 'location') alocation = urllib.basejoin(location, rlocation) child.setAttribute('location', alocation) elif child.localName == 'types': child.setAttribute('base-location', location) finally: importdoc.unlink() return location