def parse_element(name, values, array=False, complex=False): if not complex: element = wsdl('wsdl:types')('xsd:schema').add_child( 'xsd:element') complex = element.add_child("xsd:complexType") else: complex = wsdl('wsdl:types')('xsd:schema').add_child( 'xsd:complexType') element = complex element['name'] = name if values: items = values elif values is None: items = [('value', None)] else: items = [] if not array and items: all = complex.add_child("xsd:all") elif items: all = complex.add_child("xsd:sequence") for k, v in items: e = all.add_child("xsd:element") e['name'] = k if array: e[:] = {'minOccurs': "0", 'maxOccurs': "unbounded"} if v in TYPE_MAP.keys(): t = 'xsd:%s' % TYPE_MAP[v] elif v is None: t = 'xsd:anyType' elif isinstance(v, list): n = "ArrayOf%s%s" % (name, k) l = [] for d in v: l.extend(d.items()) parse_element(n, l, array=True, complex=True) t = "tns:%s" % n elif isinstance(v, dict): n = "%s%s" % (name, k) parse_element(n, v.items(), complex=True) t = "tns:%s" % n e.add_attribute('type', t)
def parse_element(name, values, array=False, complex=False): if not complex: element = wsdl('wsdl:types')('xsd:schema').add_child('xsd:element') complex = element.add_child("xsd:complexType") else: complex = wsdl('wsdl:types')('xsd:schema').add_child('xsd:complexType') element = complex element['name'] = name if values: items = values elif values is None: items = [('value', None)] else: items = [] if not array and items: all = complex.add_child("xsd:all") elif items: all = complex.add_child("xsd:sequence") for k,v in items: e = all.add_child("xsd:element") e['name'] = k if array: e[:]={'minOccurs': "0", 'maxOccurs': "unbounded"} if v in TYPE_MAP.keys(): t='xsd:%s' % TYPE_MAP[v] elif v is None: t='xsd:anyType' elif isinstance(v, list): n="ArrayOf%s%s" % (name, k) l = [] for d in v: l.extend(d.items()) parse_element(n, l, array=True, complex=True) t = "tns:%s" % n elif isinstance(v, dict): n="%s%s" % (name, k) parse_element(n, v.items(), complex=True) t = "tns:%s" % n e.add_attribute('type', t)
def wsdl(self, url, debug=False, cache=False): "Parse Web Service Description v1.1" soap_ns = { "http://schemas.xmlsoap.org/wsdl/soap/": 'soap11', "http://schemas.xmlsoap.org/wsdl/soap12/": 'soap12', } wsdl_uri = "http://schemas.xmlsoap.org/wsdl/" xsd_uri = "http://www.w3.org/2001/XMLSchema" xsi_uri = "http://www.w3.org/2001/XMLSchema-instance" get_local_name = lambda s: str((':' in s) and s.split(':')[1] or s) REVERSE_TYPE_MAP = dict([(v, k) for k, v in TYPE_MAP.items()]) def fetch(url): "Fetch a document from a URL, save it locally if cache enabled" import os, hashlib # make md5 hash of the url for caching... filename = "%s.xml" % hashlib.md5(url).hexdigest() if isinstance(cache, basestring): filename = os.path.join(cache, filename) if cache and os.path.exists(filename): if debug: print "Reading file %s" % (filename, ) f = open(filename, "r") xml = f.read() f.close() else: if debug: print "Fetching url %s" % (url, ) f = urllib.urlopen(url) xml = f.read() if cache: if debug: print "Writing file %s" % (filename, ) f = open(filename, "w") f.write(xml) f.close() return xml # Open uri and read xml: xml = fetch(url) # Parse WSDL XML: wsdl = SimpleXMLElement(xml, namespace=wsdl_uri) # detect soap prefix and uri (xmlns attributes of <definitions>) xsd_ns = None soap_uris = {} for k, v in wsdl[:]: if v in soap_ns and k.startswith("xmlns:"): soap_uris[get_local_name(k)] = v if v == xsd_uri and k.startswith("xmlns:"): xsd_ns = get_local_name(k) # Extract useful data: self.namespace = wsdl['targetNamespace'] self.documentation = unicode(wsdl('documentation', error=False) or '') services = {} bindings = {} # binding_name: binding operations = {} # operation_name: operation port_type_bindings = {} # port_type_name: binding messages = {} # message: element elements = {} # element: type def for service in wsdl.service: service_name = service['name'] if not service_name: continue # empty service? if debug: print "Processing service", service_name serv = services.setdefault(service_name, {'ports': {}}) serv['documentation'] = service['documentation'] or '' for port in service.port: binding_name = get_local_name(port['binding']) address = port('address', ns=soap_uris.values(), error=False) location = address and address['location'] or None soap_uri = address and soap_uris.get(address.get_prefix()) soap_ver = soap_uri and soap_ns.get(soap_uri) bindings[binding_name] = { 'service_name': service_name, 'location': location, 'soap_uri': soap_uri, 'soap_ver': soap_ver, } serv['ports'][port['name']] = bindings[binding_name] for binding in wsdl.binding: binding_name = binding['name'] if debug: print "Processing binding", service_name soap_binding = binding('binding', ns=soap_uris.values(), error=False) transport = soap_binding and soap_binding['transport'] or None port_type_name = get_local_name(binding['type']) bindings[binding_name].update({ 'port_type_name': port_type_name, 'transport': transport, 'operations': {}, }) port_type_bindings[port_type_name] = bindings[binding_name] for operation in binding.operation: op_name = operation['name'] op = operation('operation', ns=soap_uris.values(), error=False) action = op and op['soapAction'] d = operations.setdefault(op_name, {}) bindings[binding_name]['operations'][op_name] = d d.update({'name': op_name}) #if action: #TODO: separe operation_binding from operation if action: d["action"] = action #TODO: cleanup element/schema/types parsing: def process_element(element_name, node): "Parse and define simple element types" if debug: print "Processing element", element_name for tag in node: if tag.get_local_name() in ("annotation", "documentation"): continue elif tag.get_local_name() in ('element', 'restriction'): if debug: print element_name, "has not children!", tag children = tag # element "alias"? alias = True elif tag.children(): children = tag.children() alias = False else: if debug: print element_name, "has not children!", tag continue #TODO: abstract? d = OrderedDict() for e in children: t = e['type'] if not t: t = e['base'] # complexContent (extension)! if not t: t = 'anyType' # no type given! t = t.split(":") if len(t) > 1: ns, type_name = t else: ns, type_name = None, t[0] if element_name == type_name: continue # prevent infinite recursion uri = ns and e.get_namespace_uri(ns) or xsd_uri if uri == xsd_uri: # look for the type, None == any fn = REVERSE_TYPE_MAP.get(unicode(type_name), None) else: # complex type, postprocess later fn = elements.setdefault(unicode(type_name), OrderedDict()) if e['name'] is not None and not alias: e_name = unicode(e['name']) d[e_name] = fn else: if debug: print "complexConent/simpleType/element", element_name, "=", type_name d[None] = fn if e['maxOccurs'] == "unbounded": # it's an array... TODO: compound arrays? d.array = True if e is not None and e.get_local_name( ) == 'extension' and e.children(): # extend base element: process_element(element_name, e.children()) elements.setdefault(element_name, OrderedDict()).update(d) # check axis2 namespace at schema types attributes self.namespace = dict(wsdl.types("schema", ns=xsd_uri)[:]).get( 'targetNamespace', self.namespace) imported_schemas = {} def preprocess_schema(schema): "Find schema elements and complex types" for element in schema.children(): if element.get_local_name() in ('import', ): schema_namespace = element['namespace'] schema_location = element['schemaLocation'] if schema_location is None: if debug: print "Schema location not provided for %s!" % ( schema_namespace, ) continue if schema_location in imported_schemas: if debug: print "Schema %s already imported!" % ( schema_location, ) continue imported_schemas[schema_location] = schema_namespace if debug: print "Importing schema %s from %s" % ( schema_namespace, schema_location) # Open uri and read xml: xml = fetch(schema_location) # Parse imported XML schema (recursively): imported_schema = SimpleXMLElement(xml, namespace=xsd_uri) preprocess_schema(imported_schema) if element.get_local_name() in ('element', 'complexType', "simpleType"): element_name = unicode(element['name']) if debug: print "Parsing Element %s: %s" % ( element.get_local_name(), element_name) if element.get_local_name() == 'complexType': children = element.children() elif element.get_local_name() == 'simpleType': children = element("restriction", ns=xsd_uri) elif element.get_local_name( ) == 'element' and element['type']: children = element else: children = element.children() if children: children = children.children() elif element.get_local_name() == 'element': children = element if children: process_element(element_name, children) def postprocess_element(elements): "Fix unresolved references (elements referenced before its definition, thanks .net)" for k, v in elements.items(): if isinstance(v, OrderedDict): if v.array: elements[k] = [v] # convert arrays to python lists if v != elements: #TODO: fix recursive elements postprocess_element(v) if None in v and v[None]: # extension base? if isinstance(v[None], dict): for i, kk in enumerate(v[None]): # extend base -keep orginal order- elements[k].insert(kk, v[None][kk], i) del v[None] else: # "alias", just replace if debug: print "Replacing ", k, " = ", v[None] elements[k] = v[None] #break if isinstance(v, list): for n in v: # recurse list postprocess_element(n) # process current wsdl schema: for schema in wsdl.types("schema", ns=xsd_uri): preprocess_schema(schema) postprocess_element(elements) for message in wsdl.message: if debug: print "Processing message", message['name'] part = message('part', error=False) element = {} if part: element_name = part['element'] if not element_name: element_name = part['type'] # some uses type instead element_name = get_local_name(element_name) element = {element_name: elements.get(element_name)} messages[message['name']] = element for port_type in wsdl.portType: port_type_name = port_type['name'] if debug: print "Processing port type", port_type_name binding = port_type_bindings[port_type_name] for operation in port_type.operation: op_name = operation['name'] op = operations[op_name] op['documentation'] = unicode( operation('documentation', error=False) or '') if binding['soap_ver']: #TODO: separe operation_binding from operation (non SOAP?) input = get_local_name(operation.input['message']) output = get_local_name(operation.output['message']) op['input'] = messages[input] op['output'] = messages[output] if debug: import pprint pprint.pprint(services) return services
def wsdl(self, url, debug=False, cache=False): "Parse Web Service Description v1.1" soap_ns = { "http://schemas.xmlsoap.org/wsdl/soap/": "soap11", "http://schemas.xmlsoap.org/wsdl/soap12/": "soap12", } wsdl_uri = "http://schemas.xmlsoap.org/wsdl/" xsd_uri = "http://www.w3.org/2001/XMLSchema" xsi_uri = "http://www.w3.org/2001/XMLSchema-instance" get_local_name = lambda s: str((":" in s) and s.split(":")[1] or s) REVERSE_TYPE_MAP = dict([(v, k) for k, v in TYPE_MAP.items()]) def fetch(url): "Fetch a document from a URL, save it locally if cache enabled" import os, hashlib # make md5 hash of the url for caching... filename = "%s.xml" % hashlib.md5(url).hexdigest() if isinstance(cache, basestring): filename = os.path.join(cache, filename) if cache and os.path.exists(filename): if debug: print "Reading file %s" % (filename,) f = open(filename, "r") xml = f.read() f.close() else: if debug: print "Fetching url %s" % (url,) f = urllib.urlopen(url) xml = f.read() if cache: if debug: print "Writing file %s" % (filename,) f = open(filename, "w") f.write(xml) f.close() return xml # Open uri and read xml: xml = fetch(url) # Parse WSDL XML: wsdl = SimpleXMLElement(xml, namespace=wsdl_uri) # detect soap prefix and uri (xmlns attributes of <definitions>) xsd_ns = None soap_uris = {} for k, v in wsdl[:]: if v in soap_ns and k.startswith("xmlns:"): soap_uris[get_local_name(k)] = v if v == xsd_uri and k.startswith("xmlns:"): xsd_ns = get_local_name(k) # Extract useful data: self.namespace = wsdl["targetNamespace"] self.documentation = unicode(wsdl("documentation", error=False) or "") services = {} bindings = {} # binding_name: binding operations = {} # operation_name: operation port_type_bindings = {} # port_type_name: binding messages = {} # message: element elements = {} # element: type def for service in wsdl.service: service_name = service["name"] if not service_name: continue # empty service? if debug: print "Processing service", service_name serv = services.setdefault(service_name, {"ports": {}}) serv["documentation"] = service["documentation"] or "" for port in service.port: binding_name = get_local_name(port["binding"]) address = port("address", ns=soap_uris.values(), error=False) location = address and address["location"] or None soap_uri = address and soap_uris.get(address.get_prefix()) soap_ver = soap_uri and soap_ns.get(soap_uri) bindings[binding_name] = { "service_name": service_name, "location": location, "soap_uri": soap_uri, "soap_ver": soap_ver, } serv["ports"][port["name"]] = bindings[binding_name] for binding in wsdl.binding: binding_name = binding["name"] if debug: print "Processing binding", service_name soap_binding = binding("binding", ns=soap_uris.values(), error=False) transport = soap_binding and soap_binding["transport"] or None port_type_name = get_local_name(binding["type"]) bindings[binding_name].update({"port_type_name": port_type_name, "transport": transport, "operations": {}}) port_type_bindings[port_type_name] = bindings[binding_name] for operation in binding.operation: op_name = operation["name"] op = operation("operation", ns=soap_uris.values(), error=False) action = op and op["soapAction"] d = operations.setdefault(op_name, {}) bindings[binding_name]["operations"][op_name] = d d.update({"name": op_name}) # if action: #TODO: separe operation_binding from operation if action: d["action"] = action # TODO: cleanup element/schema/types parsing: def process_element(element_name, node): "Parse and define simple element types" if debug: print "Processing element", element_name for tag in node: if tag.get_local_name() in ("annotation", "documentation"): continue elif tag.get_local_name() in ("element", "restriction"): if debug: print element_name, "has not children!", tag children = tag # element "alias"? alias = True elif tag.children(): children = tag.children() alias = False else: if debug: print element_name, "has not children!", tag continue # TODO: abstract? d = OrderedDict() for e in children: t = e["type"] if not t: t = e["base"] # complexContent (extension)! if not t: t = "anyType" # no type given! t = t.split(":") if len(t) > 1: ns, type_name = t else: ns, type_name = None, t[0] if element_name == type_name: continue # prevent infinite recursion uri = ns and e.get_namespace_uri(ns) or xsd_uri if uri == xsd_uri: # look for the type, None == any fn = REVERSE_TYPE_MAP.get(unicode(type_name), None) else: # complex type, postprocess later fn = elements.setdefault(unicode(type_name), OrderedDict()) if e["name"] is not None and not alias: e_name = unicode(e["name"]) d[e_name] = fn else: if debug: print "complexConent/simpleType/element", element_name, "=", type_name d[None] = fn if e["maxOccurs"] == "unbounded": # it's an array... TODO: compound arrays? d.array = True if e is not None and e.get_local_name() == "extension" and e.children(): # extend base element: process_element(element_name, e.children()) elements.setdefault(element_name, OrderedDict()).update(d) # check axis2 namespace at schema types attributes self.namespace = dict(wsdl.types("schema", ns=xsd_uri)[:]).get("targetNamespace", self.namespace) imported_schemas = {} def preprocess_schema(schema): "Find schema elements and complex types" for element in schema.children(): if element.get_local_name() in ("import",): schema_namespace = element["namespace"] schema_location = element["schemaLocation"] if schema_location is None: if debug: print "Schema location not provided for %s!" % (schema_namespace,) continue if schema_location in imported_schemas: if debug: print "Schema %s already imported!" % (schema_location,) continue imported_schemas[schema_location] = schema_namespace if debug: print "Importing schema %s from %s" % (schema_namespace, schema_location) # Open uri and read xml: xml = fetch(schema_location) # Parse imported XML schema (recursively): imported_schema = SimpleXMLElement(xml, namespace=xsd_uri) preprocess_schema(imported_schema) if element.get_local_name() in ("element", "complexType", "simpleType"): element_name = unicode(element["name"]) if debug: print "Parsing Element %s: %s" % (element.get_local_name(), element_name) if element.get_local_name() == "complexType": children = element.children() elif element.get_local_name() == "simpleType": children = element("restriction", ns=xsd_uri) elif element.get_local_name() == "element" and element["type"]: children = element else: children = element.children() if children: children = children.children() elif element.get_local_name() == "element": children = element if children: process_element(element_name, children) def postprocess_element(elements): "Fix unresolved references (elements referenced before its definition, thanks .net)" for k, v in elements.items(): if isinstance(v, OrderedDict): if v.array: elements[k] = [v] # convert arrays to python lists if v != elements: # TODO: fix recursive elements postprocess_element(v) if None in v and v[None]: # extension base? if isinstance(v[None], dict): for i, kk in enumerate(v[None]): # extend base -keep orginal order- elements[k].insert(kk, v[None][kk], i) del v[None] else: # "alias", just replace if debug: print "Replacing ", k, " = ", v[None] elements[k] = v[None] # break if isinstance(v, list): for n in v: # recurse list postprocess_element(n) # process current wsdl schema: for schema in wsdl.types("schema", ns=xsd_uri): preprocess_schema(schema) postprocess_element(elements) for message in wsdl.message: if debug: print "Processing message", message["name"] part = message("part", error=False) element = {} if part: element_name = part["element"] if not element_name: element_name = part["type"] # some uses type instead element_name = get_local_name(element_name) element = {element_name: elements.get(element_name)} messages[message["name"]] = element for port_type in wsdl.portType: port_type_name = port_type["name"] if debug: print "Processing port type", port_type_name binding = port_type_bindings[port_type_name] for operation in port_type.operation: op_name = operation["name"] op = operations[op_name] op["documentation"] = unicode(operation("documentation", error=False) or "") if binding["soap_ver"]: # TODO: separe operation_binding from operation (non SOAP?) input = get_local_name(operation.input["message"]) output = get_local_name(operation.output["message"]) op["input"] = messages[input] op["output"] = messages[output] if debug: import pprint pprint.pprint(services) return services
def wsdl_parse(self, url, debug=False, cache=False): "Parse Web Service Description v1.1" if debug: print "wsdl url: %s" % url # Try to load a previously parsed wsdl: force_download = False if cache: # make md5 hash of the url for caching... filename_pkl = "%s.pkl" % hashlib.md5(url).hexdigest() if isinstance(cache, basestring): filename_pkl = os.path.join(cache, filename_pkl) if os.path.exists(filename_pkl): if debug: print "Unpickle file %s" % (filename_pkl, ) f = open(filename_pkl, "r") pkl = pickle.load(f) f.close() # sanity check: if pkl['version'][:-1] != __version__.split(" ")[0][:-1] or pkl['url'] != url: import warnings warnings.warn('version or url mismatch! discarding cached wsdl', RuntimeWarning) if debug: print 'Version:', pkl['version'], __version__ print 'URL:', pkl['url'], url force_download = True else: self.namespace = pkl['namespace'] self.documentation = pkl['documentation'] return pkl['services'] soap_ns = { "http://schemas.xmlsoap.org/wsdl/soap/": 'soap11', "http://schemas.xmlsoap.org/wsdl/soap12/": 'soap12', } wsdl_uri="http://schemas.xmlsoap.org/wsdl/" xsd_uri="http://www.w3.org/2001/XMLSchema" xsi_uri="http://www.w3.org/2001/XMLSchema-instance" get_local_name = lambda s: str((':' in s) and s.split(':')[1] or s) REVERSE_TYPE_MAP = dict([(v,k) for k,v in TYPE_MAP.items()]) def fetch(url): "Download a document from a URL, save it locally if cache enabled" # make md5 hash of the url for caching... filename = "%s.xml" % hashlib.md5(url).hexdigest() if isinstance(cache, basestring): filename = os.path.join(cache, filename) if cache and os.path.exists(filename) and not force_download: if debug: print "Reading file %s" % (filename, ) f = open(filename, "r") xml = f.read() f.close() else: if debug: print "Fetching url %s using urllib2" % (url, ) f = urllib2.urlopen(url) xml = f.read() if cache: if debug: print "Writing file %s" % (filename, ) if not os.path.isdir(cache): os.makedirs(cache) f = open(filename, "w") f.write(xml) f.close() return xml # Open uri and read xml: xml = fetch(url) # Parse WSDL XML: wsdl = SimpleXMLElement(xml, namespace=wsdl_uri) # detect soap prefix and uri (xmlns attributes of <definitions>) xsd_ns = None soap_uris = {} for k, v in wsdl[:]: if v in soap_ns and k.startswith("xmlns:"): soap_uris[get_local_name(k)] = v if v== xsd_uri and k.startswith("xmlns:"): xsd_ns = get_local_name(k) # Extract useful data: self.namespace = wsdl['targetNamespace'] self.documentation = unicode(wsdl('documentation', error=False) or '') services = {} bindings = {} # binding_name: binding operations = {} # operation_name: operation port_type_bindings = {} # port_type_name: binding messages = {} # message: element elements = {} # element: type def for service in wsdl.service: service_name=service['name'] if not service_name: continue # empty service? if debug: print "Processing service", service_name serv = services.setdefault(service_name, {'ports': {}}) serv['documentation']=service['documentation'] or '' for port in service.port: binding_name = get_local_name(port['binding']) address = port('address', ns=soap_uris.values(), error=False) location = address and address['location'] or None soap_uri = address and soap_uris.get(address.get_prefix()) soap_ver = soap_uri and soap_ns.get(soap_uri) bindings[binding_name] = {'service_name': service_name, 'location': location, 'soap_uri': soap_uri, 'soap_ver': soap_ver, } serv['ports'][port['name']] = bindings[binding_name] for binding in wsdl.binding: binding_name = binding['name'] if debug: print "Processing binding", service_name soap_binding = binding('binding', ns=soap_uris.values(), error=False) transport = soap_binding and soap_binding['transport'] or None port_type_name = get_local_name(binding['type']) bindings[binding_name].update({ 'port_type_name': port_type_name, 'transport': transport, 'operations': {}, }) port_type_bindings[port_type_name] = bindings[binding_name] for operation in binding.operation: op_name = operation['name'] op = operation('operation',ns=soap_uris.values(), error=False) action = op and op['soapAction'] d = operations.setdefault(op_name, {}) bindings[binding_name]['operations'][op_name] = d d.update({'name': op_name}) #if action: #TODO: separe operation_binding from operation if action: d["action"] = action #TODO: cleanup element/schema/types parsing: def process_element(element_name, node): "Parse and define simple element types" if debug: print "Processing element", element_name for tag in node: if tag.get_local_name() in ("annotation", "documentation"): continue elif tag.get_local_name() in ('element', 'restriction'): if debug: print element_name,"has not children!",tag children = tag # element "alias"? alias = True elif tag.children(): children = tag.children() alias = False else: if debug: print element_name,"has not children!",tag continue #TODO: abstract? d = OrderedDict() for e in children: t = e['type'] if not t: t = e['base'] # complexContent (extension)! if not t: t = 'anyType' # no type given! t = t.split(":") if len(t)>1: ns, type_name = t else: ns, type_name = None, t[0] if element_name == type_name: continue # prevent infinite recursion uri = ns and e.get_namespace_uri(ns) or xsd_uri if uri==xsd_uri: # look for the type, None == any fn = REVERSE_TYPE_MAP.get(unicode(type_name), None) else: # complex type, postprocess later fn = elements.setdefault(unicode(type_name), OrderedDict()) if e['name'] is not None and not alias: e_name = unicode(e['name']) d[e_name] = fn else: if debug: print "complexConent/simpleType/element", element_name, "=", type_name d[None] = fn if e['maxOccurs']=="unbounded": # it's an array... TODO: compound arrays? d.array = True if e is not None and e.get_local_name() == 'extension' and e.children(): # extend base element: process_element(element_name, e.children()) elements.setdefault(element_name, OrderedDict()).update(d) # check axis2 namespace at schema types attributes self.namespace = dict(wsdl.types("schema", ns=xsd_uri)[:]).get('targetNamespace', self.namespace) imported_schemas = {} def preprocess_schema(schema): "Find schema elements and complex types" for element in schema.children(): if element.get_local_name() in ('import', ): schema_namespace = element['namespace'] schema_location = element['schemaLocation'] if schema_location is None: if debug: print "Schema location not provided for %s!" % (schema_namespace, ) continue if schema_location in imported_schemas: if debug: print "Schema %s already imported!" % (schema_location, ) continue imported_schemas[schema_location] = schema_namespace if debug: print "Importing schema %s from %s" % (schema_namespace, schema_location) # Open uri and read xml: xml = fetch(schema_location) # Parse imported XML schema (recursively): imported_schema = SimpleXMLElement(xml, namespace=xsd_uri) preprocess_schema(imported_schema) if element.get_local_name() in ('element', 'complexType', "simpleType"): element_name = unicode(element['name']) if debug: print "Parsing Element %s: %s" % (element.get_local_name(),element_name) if element.get_local_name() == 'complexType': children = element.children() elif element.get_local_name() == 'simpleType': children = element("restriction", ns=xsd_uri) elif element.get_local_name() == 'element' and element['type']: children = element else: children = element.children() if children: children = children.children() elif element.get_local_name() == 'element': children = element if children: process_element(element_name, children) def postprocess_element(elements): "Fix unresolved references (elements referenced before its definition, thanks .net)" for k,v in elements.items(): if isinstance(v, OrderedDict): if v.array: elements[k] = [v] # convert arrays to python lists if v!=elements: #TODO: fix recursive elements postprocess_element(v) if None in v and v[None]: # extension base? if isinstance(v[None], dict): for i, kk in enumerate(v[None]): # extend base -keep orginal order- elements[k].insert(kk, v[None][kk], i) del v[None] else: # "alias", just replace if debug: print "Replacing ", k , " = ", v[None] elements[k] = v[None] #break if isinstance(v, list): for n in v: # recurse list postprocess_element(n) # process current wsdl schema: for schema in wsdl.types("schema", ns=xsd_uri): preprocess_schema(schema) postprocess_element(elements) for message in wsdl.message: if debug: print "Processing message", message['name'] part = message('part', error=False) element = {} if part: element_name = part['element'] if not element_name: element_name = part['type'] # some uses type instead element_name = get_local_name(element_name) element = {element_name: elements.get(element_name)} messages[message['name']] = element for port_type in wsdl.portType: port_type_name = port_type['name'] if debug: print "Processing port type", port_type_name binding = port_type_bindings[port_type_name] for operation in port_type.operation: op_name = operation['name'] op = operations[op_name] op['documentation'] = unicode(operation('documentation', error=False) or '') if binding['soap_ver']: #TODO: separe operation_binding from operation (non SOAP?) input = get_local_name(operation.input['message']) output = get_local_name(operation.output['message']) op['input'] = messages[input] op['output'] = messages[output] if debug: import pprint pprint.pprint(services) # Save parsed wsdl (cache) if cache: f = open(filename_pkl, "wb") pkl = { 'version': __version__.split(" ")[0], 'url': url, 'namespace': self.namespace, 'documentation': self.documentation, 'services': services, } pickle.dump(pkl, f) f.close() return services
def wsdl(self, url, debug=False): "Parse Web Service Description v1.1" soap_ns = { "http://schemas.xmlsoap.org/wsdl/soap/": 'soap11', "http://schemas.xmlsoap.org/wsdl/soap12/": 'soap12', } wsdl_uri = "http://schemas.xmlsoap.org/wsdl/" xsd_uri = "http://www.w3.org/2001/XMLSchema" xsi_uri = "http://www.w3.org/2001/XMLSchema-instance" get_local_name = lambda s: str((':' in s) and s.split(':')[1] or s) REVERSE_TYPE_MAP = dict([(v, k) for k, v in TYPE_MAP.items()]) # Open uri and read xml: f = urllib.urlopen(url) xml = f.read() # Parse WSDL XML: wsdl = SimpleXMLElement(xml, namespace=wsdl_uri) # detect soap prefix and uri (xmlns attributes of <definitions>) xsd_ns = None soap_uris = {} for k, v in wsdl[:]: if v in soap_ns and k.startswith("xmlns:"): soap_uris[get_local_name(k)] = v if v == xsd_uri and k.startswith("xmlns:"): xsd_ns = get_local_name(k) # Extract useful data: self.namespace = wsdl['targetNamespace'] self.documentation = unicode(wsdl('documentation', error=False) or '') services = {} bindings = {} # binding_name: binding operations = {} # operation_name: operation port_type_bindings = {} # port_type_name: binding messages = {} # message: element elements = {} # element: type def for service in wsdl.service: service_name = service['name'] if debug: print "Processing service", service_name serv = services.setdefault(service_name, {'ports': {}}) serv['documentation'] = service['documentation'] or '' for port in service.port: binding_name = get_local_name(port['binding']) address = port('address', ns=soap_uris.values(), error=False) location = address and address['location'] or None soap_uri = address and soap_uris.get(address.get_prefix()) soap_ver = soap_uri and soap_ns.get(soap_uri) bindings[binding_name] = { 'service_name': service_name, 'location': location, 'soap_uri': soap_uri, 'soap_ver': soap_ver, } serv['ports'][port['name']] = bindings[binding_name] for binding in wsdl.binding: binding_name = binding['name'] if debug: print "Processing binding", service_name soap_binding = binding('binding', ns=soap_uris.values(), error=False) transport = soap_binding and soap_binding['transport'] or None port_type_name = get_local_name(binding['type']) bindings[binding_name].update({ 'port_type_name': port_type_name, 'transport': transport, 'operations': {}, }) port_type_bindings[port_type_name] = bindings[binding_name] for operation in binding.operation: op_name = operation['name'] op = operation('operation', ns=soap_uris.values(), error=False) action = op and op['soapAction'] d = operations.setdefault(op_name, {}) bindings[binding_name]['operations'][op_name] = d d.update({'name': op_name}) #if action: #TODO: separe operation_binding from operation d["action"] = action def process_element(element_name, children): if debug: print "Processing element", element_name for tag in children: d = OrderedDict() for e in tag.children(): t = e['type'].split(":") if len(t) > 1: ns, type_name = t else: ns, type_name = xsd_ns, t[0] if ns == xsd_ns: # look for the type, None == any fn = REVERSE_TYPE_MAP.get(unicode(type_name), None) else: # complex type, postprocess later fn = elements.setdefault(unicode(type_name), OrderedDict()) e_name = unicode(e['name']) d[e_name] = fn if e['maxOccurs'] == "unbounded": # it's an array... TODO: compound arrays? d.array = True elements.setdefault(element_name, OrderedDict()).update(d) for element in wsdl.types("schema", ns=xsd_uri).children(): if element.get_local_name() in ('element', 'complexType'): element_name = unicode(element['name']) if debug: print "Parsing Element %s: %s" % (element.get_local_name(), element_name) if element.get_local_name() == 'complexType': children = element.children() else: children = element.children() if children: children = children.children() if children: process_element(element_name, children) def postprocess_element(elements): for k, v in elements.items(): if isinstance(v, OrderedDict): if v.array: elements[k] = [v] # convert arrays to python lists if v != elements: #TODO: fix recursive elements postprocess_element(v) postprocess_element(elements) for message in wsdl.message: if debug: print "Processing message", message['name'] part = message('part', error=False) element = {} if part: element_name = get_local_name(part['element']) element = {element_name: elements.get(element_name)} messages[message['name']] = element for port_type in wsdl.portType: port_type_name = port_type['name'] if debug: print "Processing port type", port_type_name binding = port_type_bindings[port_type_name] for operation in port_type.operation: op_name = operation['name'] op = operations[op_name] op['documentation'] = unicode( operation('documentation', error=False) or '') if binding['soap_ver']: #TODO: separe operation_binding from operation (non SOAP?) input = get_local_name(operation.input['message']) output = get_local_name(operation.output['message']) op['input'] = messages[input] op['output'] = messages[output] if debug: import pprint pprint.pprint(services) return services
def wsdl(self, url, debug=False): "Parse Web Service Description v1.1" soap_ns = { "http://schemas.xmlsoap.org/wsdl/soap/": 'soap11', "http://schemas.xmlsoap.org/wsdl/soap12/": 'soap12', } wsdl_uri="http://schemas.xmlsoap.org/wsdl/" xsd_uri="http://www.w3.org/2001/XMLSchema" xsi_uri="http://www.w3.org/2001/XMLSchema-instance" get_local_name = lambda s: str((':' in s) and s.split(':')[1] or s) REVERSE_TYPE_MAP = dict([(v,k) for k,v in TYPE_MAP.items()]) # Open uri and read xml: f = urllib.urlopen(url) xml = f.read() # Parse WSDL XML: wsdl = SimpleXMLElement(xml, namespace=wsdl_uri) # detect soap prefix and uri (xmlns attributes of <definitions>) xsd_ns = None soap_uris = {} for k, v in wsdl[:]: if v in soap_ns and k.startswith("xmlns:"): soap_uris[get_local_name(k)] = v if v== xsd_uri and k.startswith("xmlns:"): xsd_ns = get_local_name(k) # Extract useful data: self.namespace = wsdl['targetNamespace'] self.documentation = unicode(wsdl('documentation', error=False) or '') services = {} bindings = {} # binding_name: binding operations = {} # operation_name: operation port_type_bindings = {} # port_type_name: binding messages = {} # message: element elements = {} # element: type def for service in wsdl.service: service_name=service['name'] if debug: print "Processing service", service_name serv = services.setdefault(service_name, {'ports': {}}) serv['documentation']=service['documentation'] or '' for port in service.port: binding_name = get_local_name(port['binding']) address = port('address', ns=soap_uris.values(), error=False) location = address and address['location'] or None soap_uri = address and soap_uris.get(address.get_prefix()) soap_ver = soap_uri and soap_ns.get(soap_uri) bindings[binding_name] = {'service_name': service_name, 'location': location, 'soap_uri': soap_uri, 'soap_ver': soap_ver, } serv['ports'][port['name']] = bindings[binding_name] for binding in wsdl.binding: binding_name = binding['name'] if debug: print "Processing binding", service_name soap_binding = binding('binding', ns=soap_uris.values(), error=False) transport = soap_binding and soap_binding['transport'] or None port_type_name = get_local_name(binding['type']) bindings[binding_name].update({ 'port_type_name': port_type_name, 'transport': transport, 'operations': {}, }) port_type_bindings[port_type_name] = bindings[binding_name] for operation in binding.operation: op_name = operation['name'] op = operation('operation',ns=soap_uris.values(), error=False) action = op and op['soapAction'] d = operations.setdefault(op_name, {}) bindings[binding_name]['operations'][op_name] = d d.update({'name': op_name}) #if action: #TODO: separe operation_binding from operation d["action"] = action def process_element(element_name, children): if debug: print "Processing element", element_name for tag in children: d = OrderedDict() for e in tag.children(): t = e['type'].split(":") if len(t)>1: ns, type_name = t else: ns, type_name = xsd_ns, t[0] if ns==xsd_ns: # look for the type, None == any fn = REVERSE_TYPE_MAP.get(unicode(type_name), None) else: # complex type, postprocess later fn = elements.setdefault(unicode(type_name), OrderedDict()) e_name = unicode(e['name']) d[e_name] = fn if e['maxOccurs']=="unbounded": # it's an array... TODO: compound arrays? d.array = True elements.setdefault(element_name, OrderedDict()).update(d) for element in wsdl.types("schema", ns=xsd_uri).children(): if element.get_local_name() in ('element', 'complexType'): element_name = unicode(element['name']) if debug: print "Parsing Element %s: %s" % (element.get_local_name(),element_name) if element.get_local_name() == 'complexType': children = element.children() else: children = element.children() if children: children = children.children() if children: process_element(element_name, children) def postprocess_element(elements): for k,v in elements.items(): if isinstance(v, OrderedDict): if v.array: elements[k] = [v] # convert arrays to python lists if v!=elements: #TODO: fix recursive elements postprocess_element(v) postprocess_element(elements) for message in wsdl.message: if debug: print "Processing message", message['name'] part = message('part', error=False) element = {} if part: element_name = get_local_name(part['element']) element = {element_name: elements.get(element_name)} messages[message['name']] = element for port_type in wsdl.portType: port_type_name = port_type['name'] if debug: print "Processing port type", port_type_name binding = port_type_bindings[port_type_name] for operation in port_type.operation: op_name = operation['name'] op = operations[op_name] op['documentation'] = unicode(operation('documentation', error=False) or '') if binding['soap_ver']: #TODO: separe operation_binding from operation (non SOAP?) input = get_local_name(operation.input['message']) output = get_local_name(operation.output['message']) op['input'] = messages[input] op['output'] = messages[output] if debug: import pprint pprint.pprint(services) return services