def _load(self, url): doc = ET.parse(urllib2.urlopen(url)) extrans = doc.getroot().nsmap targetns = doc.getroot().get('targetNamespace') schemas = doc.findall(ns.expand('*/xs:schema')) for s in schemas: for k,v in extrans.items(): if k not in s.nsmap: s.nsmap[k] = v self.schemaloader.load(s, pathinfo=self.url) self.documents.append(doc) wsdls = doc.findall(ns.expand('/wsdl:import')) for w in wsdls: location = w.get('location') location = urljoin(url, location) tns = self._load(location) if tns: targetns = tns return targetns
def load(self, schema, force=False, fragment=False, pathinfo='', basecls=None): ''' Load and pre-process an XML schema. @type schema: L{ElementTree.Element} or URL @param schema: A schema to load. @type force: bool @param force: Optional. Reload an already loaded schema. @type fragment: bool @param fragment: Optional. The schema is actually a fragment of a an already-loaded schema and should be integrated with it. @type pathinfo: str @param pathinfo: Optional. A URL to help with loading the schema. Usually used by SchemaLoader to process xs:import directives. @rtype: str @return: The targetNamespace of the loaded schema ''' # Is schema already parsed if ET.iselement(schema): root = schema else: schema = urljoin(pathinfo, schema) root = ET.parse(u2.urlopen(schema)).getroot() # Get the target namespace. Exit early if we already know this schema. targetNamespace = root.get('targetNamespace') if targetNamespace in self.schemas and not (force or fragment): return targetNamespace # Add a new entry to our dictionary if not fragment: self.schemas[targetNamespace] = { 'root': root, 'types': {}, 'elements': {}, 'groups': {}, 'validator': None, 'basecls': basecls } # Update our "all namespaces" dictionary and get references to the # various subdictionaries we'll need self.allns.update(root.nsmap) self.revns.update((v,k) for k,v in root.nsmap.items() if k not in (None, 'tns')) types = self.schemas[targetNamespace]['types'] elements = self.schemas[targetNamespace]['elements'] groups = self.schemas[targetNamespace]['groups'] # Process includes includes = [] while True: # Get the list of includes inclist = root.findall(ns.expand('xs:include')) if not inclist: break for el in inclist: # remove it from the document root.remove(el) # Get the schemaLocation and compute the URL location = el.get('schemaLocation') if location in includes: # skip if we've processed this schema continue includes.append(location) url = urljoin(pathinfo, location) # Parse the XML and append it to the root document # We probably *should* include it into the place where the # xs:include node was, but for now, punt and append it # to the end of the document inc = ET.parse(u2.urlopen(url)).getroot() root.extend(inc) # Process imports for el in root.findall(ns.expand('xs:import')): location = el.get('schemaLocation') if location: self.load(location, pathinfo=pathinfo) # Find all first-level tags we care about and reference them # in the types/elements/groups dictionaries for el in root.findall(ns.expand('xs:complexType')): types[el.get('name')] = el for el in root.findall(ns.expand('xs:simpleType')): types[el.get('name')] = el for el in root.findall(ns.expand('xs:element')): elements[el.get('name')] = el for el in root.findall(ns.expand('xs:group')): groups[el.get('name')] = el # If this is a schema fragment, integrate it into the # original schema element tree in memory if fragment: realroot = self.schemas[targetNamespace]['root'] nsmap = dict(realroot.nsmap) nsmap.update(root.nsmap) attrib = dict(realroot.attrib) attrib.update(root.attrib) newroot = ET.Element(realroot.tag, attrib=attrib, nsmap=nsmap) newroot.text = realroot.text newroot.extend(realroot.getchildren()) newroot.extend(root.getchildren()) self.schemas[targetNamespace]['root'] = newroot return targetNamespace
def invoke(self, operation, *args, **kwargs): ''' Invoke a SOAP operation. ''' self._reqno += 1 retxml = kwargs.pop('__retxml__', self.retxml) timeout = kwargs.pop('__timeout__', self.timeout) transport_options = kwargs.pop('__transport__', {}) # Create an instance of the request message and initialize # the object from the arguments param = self.factory(operation.imsg) tmpl = param.__template__ for k,v in zip((t[0] for t in tmpl), args): param[k] = v for k,v in kwargs.items(): param[k] = v # Build the soap envelope and set the http headers payload = self.envelope(self.headers, param, operation.imsg) httphdr = { 'Content-Type': 'text/xml', 'SOAPAction': operation.action } httphdr.update(self.httphdr) # Construct and issue the request, read the response payload = ET.tostring(payload, pretty_print=True) log.debug('=== SOAP REQUEST ===\n%s', re.sub(r'password>.*?<', r'password>*****<', payload )) req = urllib2.Request(self.url, payload, httphdr) try: if self._inject: xml = ET.fromstring(self._inject.next()) else: if hasattr(self.transport, 'open'): rsp = self.transport.open(req, timeout=timeout, **transport_options) else: rsp = self.transport.urlopen(req, timeout=timeout, **transport_options) xml = ET.parse(rsp) except urllib2.HTTPError as ex: xml = ET.parse(ex) log.debug('=== SOAP RESPONSE ===\n%s', xmlstr(xml)) # Get the soap body retval = xml.find(ns.expand('soapenv:Body', self.nsmap)) if not retxml: # Does the body contain any nodes? if len(retval): # Get the first child and examine it retval = retval[0] namespace, tag = ns.split(retval.tag) # If it's a fault, convert it to an exception if tag == 'Fault': raise SoapFault(retval, self) # Otherwise, deserialize obj = self.factory(operation.omsg, retval) # If the deserialized # object has only one item, return that item, otherwise the # whole object # # This is so if the return value is a single primitive type # (like a string), you don't have to dig into an object just # to get at the single primitive return value if len(obj) == 1: obj = obj[0] retval = obj else: retval = None return retval
def load(self, schema, force=False, fragment=False, pathinfo='', basecls=None): ''' Load and pre-process an XML schema. @type schema: L{ElementTree.Element} or URL @param schema: A schema to load. @type force: bool @param force: Optional. Reload an already loaded schema. @type fragment: bool @param fragment: Optional. The schema is actually a fragment of a an already-loaded schema and should be integrated with it. @type pathinfo: str @param pathinfo: Optional. A URL to help with loading the schema. Usually used by SchemaLoader to process xs:import directives. @rtype: str @return: The targetNamespace of the loaded schema ''' # Is schema already parsed if ET.iselement(schema): root = schema else: schema = urljoin(pathinfo, schema) root = ET.parse(u2.urlopen(schema)).getroot() # Get the target namespace. Exit early if we already know this schema. targetNamespace = root.get('targetNamespace') if targetNamespace in self.schemas and not (force or fragment): return targetNamespace # Add a new entry to our dictionary if not fragment: self.schemas[targetNamespace] = { 'root': root, 'types': {}, 'elements': {}, 'groups': {}, 'validator': None, 'basecls': basecls } # Update our "all namespaces" dictionary and get references to the # various subdictionaries we'll need self.allns.update(root.nsmap) self.revns.update( (v, k) for k, v in root.nsmap.items() if k not in (None, 'tns')) types = self.schemas[targetNamespace]['types'] elements = self.schemas[targetNamespace]['elements'] groups = self.schemas[targetNamespace]['groups'] # Process includes includes = [] while True: # Get the list of includes inclist = root.findall(ns.expand('xs:include')) if not inclist: break for el in inclist: # remove it from the document root.remove(el) # Get the schemaLocation and compute the URL location = el.get('schemaLocation') if location in includes: # skip if we've processed this schema continue includes.append(location) url = urljoin(pathinfo, location) # Parse the XML and append it to the root document # We probably *should* include it into the place where the # xs:include node was, but for now, punt and append it # to the end of the document inc = ET.parse(u2.urlopen(url)).getroot() root.extend(inc) # Process imports for el in root.findall(ns.expand('xs:import')): location = el.get('schemaLocation') if location: self.load(location, pathinfo=pathinfo) # Find all first-level tags we care about and reference them # in the types/elements/groups dictionaries for el in root.findall(ns.expand('xs:complexType')): types[el.get('name')] = el for el in root.findall(ns.expand('xs:simpleType')): types[el.get('name')] = el for el in root.findall(ns.expand('xs:element')): elements[el.get('name')] = el for el in root.findall(ns.expand('xs:group')): groups[el.get('name')] = el # If this is a schema fragment, integrate it into the # original schema element tree in memory if fragment: realroot = self.schemas[targetNamespace]['root'] nsmap = dict(realroot.nsmap) nsmap.update(root.nsmap) attrib = dict(realroot.attrib) attrib.update(root.attrib) newroot = ET.Element(realroot.tag, attrib=attrib, nsmap=nsmap) newroot.text = realroot.text newroot.extend(realroot.getchildren()) newroot.extend(root.getchildren()) self.schemas[targetNamespace]['root'] = newroot return targetNamespace
def invoke(self, operation, *args, **kwargs): ''' Invoke a SOAP operation. ''' self._reqno += 1 retxml = kwargs.pop('__retxml__', self.retxml) timeout = kwargs.pop('__timeout__', self.timeout) transport_options = kwargs.pop('__transport__', {}) # Create an instance of the request message and initialize # the object from the arguments param = self.factory(operation.imsg) tmpl = param.__template__ for k,v in zip((t[0] for t in tmpl), args): param[k] = v for k,v in kwargs.items(): param[k] = v # Build the soap envelope and set the http headers payload = self.envelope(self.headers, param, operation.imsg) httphdr = { 'Content-Type': 'text/xml', 'SOAPAction': operation.action } httphdr.update(self.httphdr) # Construct and issue the request, read the response payload = ET.tostring(payload, pretty_print=True) log.debug('=== SOAP REQUEST ===\n%s', payload) req = urllib2.Request(self.url, payload, httphdr) try: if self._inject: xml = ET.fromstring(self._inject.next()) else: if hasattr(self.transport, 'open'): rsp = self.transport.open(req, timeout=timeout, **transport_options) else: rsp = self.transport.urlopen(req, timeout=timeout, **transport_options) xml = ET.parse(rsp) except urllib2.HTTPError as ex: xml = ET.parse(ex) log.debug('=== SOAP RESPONSE ===\n%s', xmlstr(xml)) # Get the soap body retval = xml.find(ns.expand('soapenv:Body', self.nsmap)) if not retxml: # Does the body contain any nodes? if len(retval): # Get the first child and examine it retval = retval[0] namespace, tag = ns.split(retval.tag) # If it's a fault, convert it to an exception if tag == 'Fault': raise SoapFault(retval, self) # Otherwise, deserialize obj = self.factory(operation.omsg, retval) # If the deserialized # object has only one item, return that item, otherwise the # whole object # # This is so if the return value is a single primitive type # (like a string), you don't have to dig into an object just # to get at the single primitive return value if len(obj) == 1: obj = obj[0] retval = obj else: retval = None return retval