def test_local_serialize_schema(self): from ZSI import SoapWriter from ZSI import _child_elements from xml.dom.ext.reader import PyExpat msg = self.client_module.DSQueryRegistrySoapOut() msg.DSQueryRegistryResult = msg.new_DSQueryRegistryResult() msg.DSQueryRegistryResult.Any = 'hi' input = open('wsdl/nvo-admin.wsdl').read() reader = PyExpat.Reader() dom = reader.fromString(input) dnode = _child_elements(dom)[0] tnode = _child_elements(dnode)[0] snode = _child_elements(tnode)[0] msg.DSQueryRegistryResult.Schema = snode sw = SoapWriter() sw.serialize(msg) soap = str(sw) print soap ps = ParsedSoap(soap) pyobj = ps.Parse(msg.typecode) self.failUnlessEqual(pyobj.DSQueryRegistryResult.Any, msg.DSQueryRegistryResult.Any) self.failUnless(_is_element(pyobj.DSQueryRegistryResult.Schema)) print _get_element_nsuri_name(pyobj.DSQueryRegistryResult.Schema) self.failUnlessEqual(_get_element_nsuri_name(pyobj.DSQueryRegistryResult.Schema), (u'http://www.w3.org/2001/XMLSchema', u'schema'))
def test_local_serialize_schema(self): from ZSI import SoapWriter from ZSI import _child_elements from xml.dom.ext.reader import PyExpat msg = self.client_module.DSQueryRegistrySoapOut() msg.DSQueryRegistryResult = msg.new_DSQueryRegistryResult() msg.DSQueryRegistryResult.Any = 'hi' input = open('wsdl/nvo-admin.wsdl').read() reader = PyExpat.Reader() dom = reader.fromString(input) dnode = _child_elements(dom)[0] tnode = _child_elements(dnode)[0] snode = _child_elements(tnode)[0] msg.DSQueryRegistryResult.Schema = snode sw = SoapWriter() sw.serialize(msg) soap = str(sw) print(soap) ps = ParsedSoap(soap) pyobj = ps.Parse(msg.typecode) self.assertEqual(pyobj.DSQueryRegistryResult.Any, msg.DSQueryRegistryResult.Any) self.assertTrue(_is_element(pyobj.DSQueryRegistryResult.Schema)) print(_get_element_nsuri_name(pyobj.DSQueryRegistryResult.Schema)) self.assertEqual( _get_element_nsuri_name(pyobj.DSQueryRegistryResult.Schema), ('http://www.w3.org/2001/XMLSchema', 'schema'))
def parse(self, elt, ps): (ns,type) = self.checkname(elt, ps) if not type and self.nilled(elt, ps): return None if len(_children(elt)) == 0: href = _find_href(elt) if not href: if self.optional: return None raise EvaluateException('Non-optional Any missing', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) (ns,type) = self.checktype(elt, ps) if not type and elt.namespaceURI == SOAP.ENC: ns,type = SOAP.ENC, elt.localName if not type or (ns,type) == (SOAP.ENC,'Array'): if self.aslist or _find_arraytype(elt): return [ Any(aslist=self.aslist).parse(e, ps) for e in _child_elements(elt) ] if len(_child_elements(elt)) == 0: raise EvaluateException("Any cannot parse untyped element", ps.Backtrace(elt)) return self.parse_into_dict_or_list(elt, ps) parser = Any.parsemap.get((ns,type)) if not parser and _is_xsd_or_soap_ns(ns): parser = Any.parsemap.get((None,type)) if not parser: raise EvaluateException('''Any can't parse element''', ps.Backtrace(elt)) return parser.parse(elt, ps)
def parse(self, elt, ps): self.checkname(elt, ps) if self.nilled(elt, ps): return None p = self.tc.parse if self.aslist: v = [] for c in _child_elements(elt): d = p(c, ps) v.append((d['key'], d['value'])) else: v = {} for c in _child_elements(elt): d = p(c, ps) v[d['key']] = d['value'] return v
def FaultFromFaultMessage(ps): '''Parse the message as a fault. ''' d = { 'faultcode': None, 'faultstring': None, 'faultactor': None, 'detail': None, } for elt in _child_elements(ps.body_root): n = elt.localName if n == 'detail': d['detail'] = _child_elements(elt) if n in [ 'faultcode', 'faultstring', 'faultactor' ]: d[n] = ''.join([E.nodeValue for E in _children(elt) if E.nodeType in [ _Node.TEXT_NODE, _Node.CDATA_SECTION_NODE ]]) return Fault(d['faultcode'], d['faultstring'], d['faultactor'], d['detail'])
def XML(self, uri, tc, ps, **keywords): content = self.get(uri) if content: dom = ps.readerclass().fromStream(content) return _child_elements(dom)[0] if not self.next: raise EvaluateException("Unresolvable URI " + uri) return self.next.XML(uri, tc, ps, **keywords)
def parse_into_dict_or_list(self, elt, ps): c = _child_elements(elt) count = len(c) v = {} if count == 0: href = _find_href(elt) if not href: return v elt = ps.FindLocalHREF(href, elt) self.checktype(elt, ps) c = _child_elements(elt) count = len(c) if count == 0: return self.listify(v) if self.nilled(elt, ps): return None for c_elt in c: v[str(c_elt.nodeName)] = self.parse(c_elt, ps) return self.listify(v)
def parse(self, elt, ps): href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Array has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) if self.nilled(elt, ps): return None if not _find_arraytype(elt) and not self.undeclared: raise EvaluateException('Array expected', ps.Backtrace(elt)) t = _find_type(elt) if t: pass # XXX should check the type, but parsing that is hairy. offset = self.parse_offset(elt, ps) v, vlen = [], 0 if offset and not self.sparse: while vlen < offset: vlen += 1 v.append(self.fill) for c in _child_elements(elt): item = self.ofwhat.parse(c, ps) position = self.parse_position(c, ps) or offset if self.sparse: v.append((position, item)) else: while offset < position: offset += 1 v.append(self.fill) v.append(item) offset += 1 return v
def Receive(self, replytype, **kw): '''Parse message, create Python object. KeyWord data: faults -- list of WSDL operation.fault typecodes wsaction -- If using WS-Address, must specify Action value we expect to receive. ''' self.ReceiveSOAP(**kw) ps = self.ps tp = _find_type(ps.body_root) isarray = ((type(tp) in (tuple,list) and tp[1] == 'Array') or _find_arraytype(ps.body_root)) if self.typesmodule is None or isarray: return _Binding.Receive(self, replytype, **kw) if ps.IsAFault(): msg = FaultFromFaultMessage(ps) raise FaultException(msg) tc = replytype if hasattr(replytype, 'typecode'): tc = replytype.typecode #Ignore response wrapper reply = {} for elt in _child_elements(ps.body_root): name = str(elt.localName) reply[name] = self.__parse_child(elt) if self.address is not None: self.address.checkResponse(ps, kw.get('wsaction')) return reply
def XML(self, uri, tc, ps, **keywords): content = self.get(uri) if content: dom = ps.readerclass().fromStream(content) return _child_elements(dom)[0] if not self.__next__: raise EvaluateException("Unresolvable URI " + uri) return self.next.XML(uri, tc, ps, **keywords)
def parse(self, elt, ps): href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Array has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) if self.nilled(elt, ps): return Nilled if not _find_arraytype(elt) and self.undeclared is False: raise EvaluateException('Array expected', ps.Backtrace(elt)) t = _find_type(elt) if t: pass # XXX should check the type, but parsing that is hairy. offset = self.parse_offset(elt, ps) v, vlen = [], 0 if offset and not self.sparse: while vlen < offset: vlen += 1 v.append(self.fill) for c in _child_elements(elt): item = self.ofwhat.parse(c, ps) position = self.parse_position(c, ps) or offset if self.sparse: v.append((position, item)) else: while offset < position: offset += 1 v.append(self.fill) v.append(item) offset += 1 return v
def Receive(self, replytype, **kw): '''Parse message, create Python object. KeyWord data: faults -- list of WSDL operation.fault typecodes wsaction -- If using WS-Address, must specify Action value we expect to receive. ''' self.ReceiveSOAP(**kw) ps = self.ps tp = _find_type(ps.body_root) isarray = ((type(tp) in (tuple, list) and tp[1] == 'Array') or _find_arraytype(ps.body_root)) if self.typesmodule is None or isarray: return _Binding.Receive(self, replytype, **kw) if ps.IsAFault(): msg = FaultFromFaultMessage(ps) raise FaultException(msg) tc = replytype if hasattr(replytype, 'typecode'): tc = replytype.typecode #Ignore response wrapper reply = {} for elt in _child_elements(ps.body_root): name = str(elt.localName) reply[name] = self.__parse_child(elt) if self.address is not None: self.address.checkResponse(ps, kw.get('wsaction')) return reply
def Receive(self, replytype=None, **kw): '''Parse message, create Python object. if replytype is None, use TC.Any to dynamically parse; otherwise it can be a Python class or the typecode to use in parsing. ''' self.ReceiveSOAP(**kw) if self.ps.IsAFault(): msg = FaultFromFaultMessage(self.ps) raise FaultException(msg) if replytype is None: tc = TC.Any(aslist=1) # if the message is RPC style, skip the fooBarResponse elt_name = '%s' % self.ps.body_root.localName if elt_name.find('Response') > 0: data = _child_elements(self.ps.body_root) else: data = [self.ps.body_root] if len(data) == 0: return None # check for array type, loop and process if found for attr in _attrs(data[0]): if attr.localName.find('arrayType') >= 0: data = _child_elements(data[0]) toReturn = [] for node in data: type = node.localName # handle case where multiple elements are returned if type.find('element') >= 0: node = _child_elements(node)[0] type = node.localName toReturn.append(self.__parse(node, type)) return toReturn # parse a complex or primitive type and return it type = data[0].localName return self.__parse(data[0], type) elif hasattr(replytype, 'typecode'): tc = replytype.typecode else: tc = replytype return self.ps.Parse(tc)
def XML(uri, tc, ps, **keywords): '''Resolve a URI and return its content as an XML DOM. ''' source = urllib.request.urlopen(uri, **keywords) enc = source.info().getencoding() if enc in ['7bit', '8bit', 'binary']: data = source else: data = StringIO.StringIO() mimetools.decode(source, data, enc) data.seek(0) dom = ps.readerclass().fromStream(data) return _child_elements(dom)[0]
def parse(self, elt, ps): if not self.wrapped: return elt c = _child_elements(elt) if not c: href = _find_href(elt) if not href: if self.optional: return None raise EvaluateException('Embedded XML document missing', ps.Backtrace(elt)) if href[0] != '#': return ps.ResolveHREF(href, self) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) if _find_encstyle(elt) != "": #raise EvaluateException('Embedded XML has unknown encodingStyle', # ps.Backtrace(elt) pass if len(c) != 1: raise EvaluateException('Embedded XML has more than one child', ps.Backtrace(elt)) if self.copyit: return c[0].cloneNode(1) return c[0]
def _Dispatch(ps, modules, SendResponse, SendFault, docstyle=0, nsdict={}, typesmodule=None, rpc=None, **kw): """Find a handler for the SOAP request in ps; search modules. Call SendResponse or SendFault to send the reply back, appropriately. """ global _client_binding try: what = ps.body_root.localName # See what modules have the element name. if modules is None: modules = (sys.modules["__main__"],) handlers = [getattr(m, what) for m in modules if hasattr(m, what)] if len(handlers) == 0: raise TypeError("Unknown method " + what) # Of those modules, see who's callable. handlers = [h for h in handlers if callable(h)] if len(handlers) == 0: raise TypeError("Unimplemented method " + what) if len(handlers) > 1: raise TypeError("Multiple implementations found: " + ` handlers `) handler = handlers[0] _client_binding = ClientBinding(ps) if docstyle: result = handler(ps.body_root) tc = TC.XML(aslist=1, pname=what + "Response") else: data = _child_elements(ps.body_root) if len(data) == 0: arg = [] else: try: try: type = data[0].localName tc = getattr(typesmodule, type).typecode except Exception, e: tc = TC.Any() arg = [tc.parse(e, ps) for e in data] except EvaluateException, e: SendFault(FaultFromZSIException(e), **kw) return
def parse(self, elt, ps): debug = self.logger.debugOn() debug and self.logger.debug('parse') xtype = self.checkname(elt, ps) if self.type and xtype not in [self.type, (None, None)]: if not isinstance(self, TypeDefinition): raise EvaluateException(\ 'ComplexType for %s has wrong type(%s), looking for %s' % (self.pname, self.checktype(elt,ps), self.type), ps.Backtrace(elt)) else: #TODO: mabye change MRO to handle this debug and self.logger.debug('delegate to substitute type') what = TypeDefinition.getSubstituteType(self, elt, ps) return what.parse(elt, ps) href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Struct has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) count = len(c) if self.nilled(elt, ps): return Nilled # Create the object. if self.pyclass: # type definition must be informed of element tag (nspname,pname), # element declaration is initialized with a tag. try: pyobj = self.pyclass() except Exception, e: raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \ %(self.nspname, self.pname, self.pyclass.__name__, str(e)))
def parse(self, elt, ps): debug = self.logger.debugOn() debug and self.logger.debug('parse') xtype = self.checkname(elt, ps) if self.type and xtype not in [ self.type, (None,None) ]: if not isinstance(self, TypeDefinition): raise EvaluateException(\ 'ComplexType for %s has wrong type(%s), looking for %s' % (self.pname, self.checktype(elt,ps), self.type), ps.Backtrace(elt)) else: #TODO: mabye change MRO to handle this debug and self.logger.debug('delegate to substitute type') what = TypeDefinition.getSubstituteType(self, elt, ps) return what.parse(elt, ps) href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Struct has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) count = len(c) if self.nilled(elt, ps): return Nilled # Create the object. if self.pyclass: # type definition must be informed of element tag (nspname,pname), # element declaration is initialized with a tag. try: pyobj = self.pyclass() except Exception, e: raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \ %(self.nspname, self.pname, self.pyclass.__name__, str(e)))
def __init__(self, input, readerclass=None, keepdom=False, trailers=False, resolver=None, envelope=True, **kw): """Initialize. Keyword arguments: trailers -- allow trailer elments (default is zero) resolver -- function (bound method) to resolve URI's readerclass -- factory class to create a reader keepdom -- do not release the DOM envelope -- look for a SOAP envelope. """ self.readerclass = readerclass self.keepdom = keepdom if not self.readerclass: if self.defaultReaderClass != None: self.readerclass = self.defaultReaderClass else: from xml.dom.ext.reader import PyExpat self.readerclass = PyExpat.Reader try: self.reader = self.readerclass() if type(input) in _stringtypes: self.dom = self.reader.fromString(input) else: self.dom = self.reader.fromStream(input) except Exception as e: # Is this in the header? Your guess is as good as mine. # raise ParseException("Can't parse document (" + \ # str(e.__class__) + "): " + str(e), 0) raise self.ns_cache = {id(self.dom): {"xml": XMLNS.XML, "xmlns": XMLNS.BASE, "": ""}} self.trailers, self.resolver, self.id_cache = trailers, resolver, {} # Exactly one child element c = [E for E in _children(self.dom) if E.nodeType == _Node.ELEMENT_NODE] if len(c) == 0: raise ParseException("Document has no Envelope", 0) if len(c) != 1: raise ParseException("Document has extra child elements", 0) if envelope is False: self.body_root = c[0] return # And that one child must be the Envelope elt = c[0] if elt.localName != "Envelope" or elt.namespaceURI != SOAP.ENV: raise ParseException('Document has "' + elt.localName + '" element, not Envelope', 0) self._check_for_legal_children("Envelope", elt) for a in _attrs(elt): name = a.nodeName if name.find(":") == -1 and name not in ["xmlns", "id"]: raise ParseException('Unqualified attribute "' + name + '" in Envelope', 0) self.envelope = elt if not _valid_encoding(self.envelope): raise ParseException("Envelope has invalid encoding", 0) # Get Envelope's child elements. c = [E for E in _children(self.envelope) if E.nodeType == _Node.ELEMENT_NODE] if len(c) == 0: raise ParseException("Envelope is empty (no Body)", 0) # Envelope's first child might be the header; if so, nip it off. elt = c[0] if elt.localName == "Header" and elt.namespaceURI == SOAP.ENV: self._check_for_legal_children("Header", elt) self._check_for_pi_nodes(_children(elt), 1) self.header = c.pop(0) self.header_elements = _child_elements(self.header) else: self.header, self.header_elements = None, [] # Now the first child must be the body if len(c) == 0: raise ParseException("Envelope has header but no Body", 0) elt = c.pop(0) if elt.localName != "Body" or elt.namespaceURI != SOAP.ENV: if self.header: raise ParseException('Header followed by "' + elt.localName + '" element, not Body', 0, elt, self.dom) else: raise ParseException('Document has "' + elt.localName + '" element, not Body', 0, elt, self.dom) self._check_for_legal_children("Body", elt, 0) self._check_for_pi_nodes(_children(elt), 0) self.body = elt if not _valid_encoding(self.body): raise ParseException("Body has invalid encoding", 0) # Trailer elements. if not self.trailers: if len(c): raise ParseException("Element found after Body", 0, elt, self.dom) # Don't set self.trailer_elements = []; if user didn't ask # for trailers we *want* to throw an exception. else: self.trailer_elements = c for elt in self.trailer_elements: if not elt.namespaceURI: raise ParseException("Unqualified trailer element", 0, elt, self.dom) # Find the serialization root. Divide the Body children into # root (root=1), no (root=0), maybe (no root attribute). self.body_root, no, maybe = None, [], [] for elt in _child_elements(self.body): root = _find_root(elt) if root == "1": if self.body_root: raise ParseException("Multiple seralization roots found", 0, elt, self.dom) self.body_root = elt elif root == "0": no.append(elt) elif not root: maybe.append(elt) else: raise ParseException("Illegal value for root attribute", 0, elt, self.dom) # If we didn't find a root, get the first one that didn't # say "not me", unless they all said "not me." if self.body_root is None: if len(maybe): self.body_root = maybe[0] else: raise ParseException("No serialization root found", 0, self.body, self.dom) if not _valid_encoding(self.body_root): raise ParseException("Invalid encoding", 0, elt, self.dom) # Now get all the non-roots (in order!). rootid = id(self.body_root) self.data_elements = [E for E in _child_elements(self.body) if id(E) != rootid] self._check_for_pi_nodes(self.data_elements, 0)
def parse(self, elt, ps): debug = self.logger.debugOn() debug and self.logger.debug('parse') xtype = self.checkname(elt, ps) if self.type and xtype not in [ self.type, (None,None) ]: if not isinstance(self, TypeDefinition): raise EvaluateException(\ 'ComplexType for %s has wrong type(%s), looking for %s' % (self.pname, self.checktype(elt,ps), self.type), ps.Backtrace(elt)) else: #TODO: mabye change MRO to handle this debug and self.logger.debug('delegate to substitute type') what = TypeDefinition.getSubstituteType(self, elt, ps) return what.parse(elt, ps) href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Struct has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) count = len(c) if self.nilled(elt, ps): return Nilled # Create the object. v = {} # parse all attributes contained in attribute_typecode_dict (user-defined attributes), # the values (if not None) will be keyed in self.attributes dictionary. attributes = self.parse_attributes(elt, ps) if attributes: v[self.attrs_aname] = attributes #MIXED if self.mixed is True: v[self.mixed_aname] = self.simple_value(elt,ps, mixed=True) # Clone list of kids (we null it out as we process) c, crange = c[:], range(len(c)) # Loop over all items we're expecting if debug: self.logger.debug("ofwhat: %s",str(self.ofwhat)) any = None for i,what in [ (i, self.ofwhat[i]) for i in range(len(self.ofwhat)) ]: # retrieve typecode if it is hidden if callable(what): what = what() # Loop over all available kids if debug: self.logger.debug("what: (%s,%s)", what.nspname, what.pname) for j,c_elt in [ (j, c[j]) for j in crange if c[j] ]: if debug: self.logger.debug("child node: (%s,%s)", c_elt.namespaceURI, c_elt.tagName) if what.name_match(c_elt): # Parse value, and mark this one done. try: value = what.parse(c_elt, ps) except EvaluateException, e: #what = _get_substitute_element(c_elt, what) #value = what.parse(c_elt, ps) raise if what.maxOccurs > 1: if v.has_key(what.aname): v[what.aname].append(value) else: v[what.aname] = [value] c[j] = None continue else: v[what.aname] = value c[j] = None break else: if debug: self.logger.debug("no element (%s,%s)", what.nspname, what.pname) # No match; if it was supposed to be here, that's an error. if self.inorder is True and i == j: raise EvaluateException('Out of order complexType', ps.Backtrace(c_elt)) else: # only supporting 1 <any> declaration in content. if isinstance(what,AnyElement): any = what elif hasattr(what, 'default'): v[what.aname] = what.default elif what.minOccurs > 0 and not v.has_key(what.aname): raise EvaluateException('Element "' + what.aname + \ '" missing from complexType', ps.Backtrace(elt))
def _Dispatch(ps, modules, SendResponse, SendFault, nsdict={}, typesmodule=None, gettypecode=gettypecode, rpc=False, docstyle=False, **kw): '''Find a handler for the SOAP request in ps; search modules. Call SendResponse or SendFault to send the reply back, appropriately. Behaviors: default -- Call "handler" method with pyobj representation of body root, and return a self-describing request (w/typecode). Parsing done via a typecode from typesmodule, or Any. docstyle -- Call "handler" method with ParsedSoap instance and parse result with an XML typecode (DOM). Behavior, wrap result in a body_root "Response" appended message. rpc -- Specify RPC wrapper of result. Behavior, ignore body root (RPC Wrapper) of request, parse all "parts" of message via individual typecodes. Expect the handler to return the parts of the message, whether it is a dict, single instance, or a list try to serialize it as a Struct but if this is not possible put it in an Array. Parsing done via a typecode from typesmodule, or Any. ''' global _client_binding try: what = str(ps.body_root.localName) # See what modules have the element name. if modules is None: modules = ( sys.modules['__main__'], ) handlers = [ getattr(m, what) for m in modules if hasattr(m, what) ] if len(handlers) == 0: raise TypeError("Unknown method " + what) # Of those modules, see who's callable. handlers = [ h for h in handlers if isinstance(h, collections.Callable) ] if len(handlers) == 0: raise TypeError("Unimplemented method " + what) if len(handlers) > 1: raise TypeError("Multiple implementations found: " + repr(handlers)) handler = handlers[0] _client_binding = ClientBinding(ps) if docstyle: result = handler(ps.body_root) tc = TC.XML(aslist=1, pname=what+'Response') elif not rpc: try: tc = gettypecode(typesmodule, ps.body_root) except Exception: tc = TC.Any() try: arg = tc.parse(ps.body_root, ps) except EvaluateException as ex: SendFault(FaultFromZSIException(ex), **kw) return try: result = handler(*arg) except Exception as ex: SendFault(FaultFromZSIException(ex), **kw) try: tc = result.typecode except AttributeError as ex: SendFault(FaultFromZSIException(ex), **kw) elif typesmodule is not None: kwargs = {} for e in _child_elements(ps.body_root): try: tc = gettypecode(typesmodule, e) except Exception: tc = TC.Any() try: kwargs[str(e.localName)] = tc.parse(e, ps) except EvaluateException as ex: SendFault(FaultFromZSIException(ex), **kw) return result = handler(**kwargs) aslist = False # make sure data is wrapped, try to make this a Struct if type(result) in _seqtypes: for o in result: aslist = hasattr(result, 'typecode') if aslist: break elif type(result) is not dict: aslist = not hasattr(result, 'typecode') result = (result,) tc = TC.Any(pname=what+'Response', aslist=aslist) else: # if this is an Array, call handler with list # if this is an Struct, call handler with dict tp = _find_type(ps.body_root) isarray = ((type(tp) in (tuple,list) and tp[1] == 'Array') or _find_arraytype(ps.body_root)) data = _child_elements(ps.body_root) tc = TC.Any() if isarray and len(data) == 0: result = handler() elif isarray: try: arg = [ tc.parse(e, ps) for e in data ] except EvaluateException as e: #SendFault(FaultFromZSIException(e), **kw) SendFault(RuntimeError("THIS IS AN ARRAY: %s" %isarray)) return result = handler(*arg) else: try: kwarg = dict([ (str(e.localName),tc.parse(e, ps)) for e in data ]) except EvaluateException as e: SendFault(FaultFromZSIException(e), **kw) return result = handler(**kwarg) # reponse typecode #tc = getattr(result, 'typecode', TC.Any(pname=what+'Response')) tc = TC.Any(pname=what+'Response') sw = SoapWriter(nsdict=nsdict) sw.serialize(result, tc) return SendResponse(str(sw), **kw) except Fault as e: return SendFault(e, **kw) except Exception as e: # Something went wrong, send a fault. return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
try: result = handler(arg) except Exception,ex: SendFault(FaultFromZSIException(ex), **kw) return try: tc = result.typecode except AttributeError,ex: SendFault(FaultFromZSIException(ex), **kw) return elif typesmodule is not None: kwargs = {} for e in _child_elements(ps.body_root): try: tc = gettypecode(typesmodule, e) except Exception: tc = TC.Any() try: kwargs[str(e.localName)] = tc.parse(e, ps) except EvaluateException, ex: SendFault(FaultFromZSIException(ex), **kw) return result = handler(**kwargs) aslist = False # make sure data is wrapped, try to make this a Struct if type(result) in _seqtypes:
def _Dispatch(ps, modules, SendResponse, SendFault, nsdict={}, typesmodule=None, gettypecode=gettypecode, rpc=False, docstyle=False, **kw): '''Find a handler for the SOAP request in ps; search modules. Call SendResponse or SendFault to send the reply back, appropriately. Behaviors: default -- Call "handler" method with pyobj representation of body root, and return a self-describing request (w/typecode). Parsing done via a typecode from typesmodule, or Any. docstyle -- Call "handler" method with ParsedSoap instance and parse result with an XML typecode (DOM). Behavior, wrap result in a body_root "Response" appended message. rpc -- Specify RPC wrapper of result. Behavior, ignore body root (RPC Wrapper) of request, parse all "parts" of message via individual typecodes. Expect the handler to return the parts of the message, whether it is a dict, single instance, or a list try to serialize it as a Struct but if this is not possible put it in an Array. Parsing done via a typecode from typesmodule, or Any. ''' global _client_binding try: what = str(ps.body_root.localName) # See what modules have the element name. if modules is None: modules = ( sys.modules['__main__'], ) handlers = [ getattr(m, what) for m in modules if hasattr(m, what) ] if len(handlers) == 0: raise TypeError("Unknown method " + what) # Of those modules, see who's callable. handlers = [ h for h in handlers if callable(h) ] if len(handlers) == 0: raise TypeError("Unimplemented method " + what) if len(handlers) > 1: raise TypeError("Multiple implementations found: %s" % handlers) handler = handlers[0] _client_binding = ClientBinding(ps) if docstyle: result = handler(ps.body_root) tc = TC.XML(aslist=1, pname=what+'Response') elif not rpc: try: tc = gettypecode(typesmodule, ps.body_root) except Exception: tc = TC.Any() try: arg = tc.parse(ps.body_root, ps) except EvaluateException as ex: SendFault(FaultFromZSIException(ex), **kw) return try: result = handler(arg) except Exception as ex: SendFault(FaultFromZSIException(ex), **kw) return try: tc = result.typecode except AttributeError as ex: SendFault(FaultFromZSIException(ex), **kw) return elif typesmodule is not None: kwargs = {} for e in _child_elements(ps.body_root): try: tc = gettypecode(typesmodule, e) except Exception: tc = TC.Any() try: kwargs[str(e.localName)] = tc.parse(e, ps) except EvaluateException as ex: SendFault(FaultFromZSIException(ex), **kw) return result = handler(**kwargs) aslist = False # make sure data is wrapped, try to make this a Struct if isinstance(result,_seqtypes): for _ in result: aslist = hasattr(result, 'typecode') if aslist: break elif not isinstance(result, dict): aslist = not hasattr(result, 'typecode') result = (result,) tc = TC.Any(pname=what+'Response', aslist=aslist) else: # if this is an Array, call handler with list # if this is an Struct, call handler with dict tp = _find_type(ps.body_root) isarray = ((isinstance(tp, (tuple,list)) and tp[1] == 'Array') or _find_arraytype(ps.body_root)) data = _child_elements(ps.body_root) tc = TC.Any() if isarray and len(data) == 0: result = handler() elif isarray: try: arg = [ tc.parse(e, ps) for e in data ] except EvaluateException as e: #SendFault(FaultFromZSIException(e), **kw) SendFault(RuntimeError("THIS IS AN ARRAY: %s" %isarray)) return result = handler(*arg) else: try: kwarg = dict([ (str(e.localName),tc.parse(e, ps)) for e in data ]) except EvaluateException as e: SendFault(FaultFromZSIException(e), **kw) return result = handler(**kwarg) # reponse typecode #tc = getattr(result, 'typecode', TC.Any(pname=what+'Response')) tc = TC.Any(pname=what+'Response') sw = SoapWriter(nsdict=nsdict) sw.serialize(result, tc) return SendResponse(str(sw), **kw) except Fault as e: return SendFault(e, **kw) except Exception as e: # Something went wrong, send a fault. return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)
def parse(self, elt, ps): debug = self.logger.debugOn() debug and self.logger.debug('parse') xtype = self.checkname(elt, ps) if self.type and xtype not in [self.type, (None, None)]: if not isinstance(self, TypeDefinition): raise EvaluateException(\ 'ComplexType for %s has wrong type(%s), looking for %s' % (self.pname, self.checktype(elt,ps), self.type), ps.Backtrace(elt)) else: #TODO: mabye change MRO to handle this debug and self.logger.debug('delegate to substitute type') what = TypeDefinition.getSubstituteType(self, elt, ps) return what.parse(elt, ps) href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Struct has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) count = len(c) if self.nilled(elt, ps): return Nilled # Create the object. v = {} # parse all attributes contained in attribute_typecode_dict (user-defined attributes), # the values (if not None) will be keyed in self.attributes dictionary. attributes = self.parse_attributes(elt, ps) if attributes: v[self.attrs_aname] = attributes #MIXED if self.mixed is True: v[self.mixed_aname] = self.simple_value(elt, ps, mixed=True) # Clone list of kids (we null it out as we process) c, crange = c[:], range(len(c)) # Loop over all items we're expecting if debug: self.logger.debug("ofwhat: %s", str(self.ofwhat)) any = None for i, what in [(i, self.ofwhat[i]) for i in range(len(self.ofwhat))]: # retrieve typecode if it is hidden if callable(what): what = what() # Loop over all available kids if debug: self.logger.debug("what: (%s,%s)", what.nspname, what.pname) for j, c_elt in [(j, c[j]) for j in crange if c[j]]: # Parse value, and mark this one done. if debug: self.logger.debug("child node: (%s,%s)", c_elt.namespaceURI, c_elt.tagName) match = False if what.name_match(c_elt): match = True value = what.parse(c_elt, ps) else: # substitutionGroup head must be a global element declaration # if successful delegate to matching GED subwhat = _get_substitute_element(what, c_elt, ps) if subwhat: match = True value = subwhat.parse(c_elt, ps) if debug: self.logger.debug("substitutionGroup: %s", subwhat) if match: if what.maxOccurs > 1: if v.has_key(what.aname): v[what.aname].append(value) else: v[what.aname] = [value] c[j] = None continue else: v[what.aname] = value c[j] = None break if debug: self.logger.debug("no element (%s,%s)", what.nspname, what.pname) # No match; if it was supposed to be here, that's an error. if self.inorder is True and i == j: raise EvaluateException('Out of order complexType', ps.Backtrace(c_elt)) else: # only supporting 1 <any> declaration in content. if isinstance(what, AnyElement): any = what elif hasattr(what, 'default'): v[what.aname] = what.default elif what.minOccurs > 0 and not v.has_key(what.aname): raise EvaluateException('Element "' + what.aname + \ '" missing from complexType', ps.Backtrace(elt)) # Look for wildcards and unprocessed children # XXX Stick all this stuff in "any", hope for no collisions if any is not None: occurs = 0 v[any.aname] = [] for j, c_elt in [(j, c[j]) for j in crange if c[j]]: value = any.parse(c_elt, ps) if any.maxOccurs == UNBOUNDED or any.maxOccurs > 1: v[any.aname].append(value) else: v[any.aname] = value occurs += 1 # No such thing as nillable <any> if any.maxOccurs == 1 and occurs == 0: v[any.aname] = None elif occurs < any.minOccurs or (any.maxOccurs != UNBOUNDED and any.maxOccurs < occurs): raise EvaluateException( 'occurances of <any> elements(#%d) bound by (%d,%s)' % (occurs, any.minOccurs, str(any.maxOccurs)), ps.Backtrace(elt)) if not self.pyclass: return v # type definition must be informed of element tag (nspname,pname), # element declaration is initialized with a tag. try: pyobj = self.pyclass() except Exception, e: raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \ %(self.nspname, self.pname, self.pyclass.__name__, str(e)))
SendFault(FaultFromZSIException(ex), **kw) return try: result = handler(*arg) except Exception, ex: SendFault(FaultFromZSIException(ex), **kw) try: tc = result.typecode except AttributeError, ex: SendFault(FaultFromZSIException(ex), **kw) elif typesmodule is not None: kwargs = {} for e in _child_elements(ps.body_root): try: tc = gettypecode(typesmodule, e) except Exception: tc = TC.Any() try: kwargs[str(e.localName)] = tc.parse(e, ps) except EvaluateException, ex: SendFault(FaultFromZSIException(ex), **kw) return result = handler(**kwargs) aslist = False # make sure data is wrapped, try to make this a Struct if type(result) in _seqtypes:
def parse(self, elt, ps): debug = self.logger.debugOn() debug and self.logger.debug('parse') xtype = self.checkname(elt, ps) if self.type and xtype not in [ self.type, (None,None) ]: if not isinstance(self, TypeDefinition): raise EvaluateException(\ 'ComplexType for %s has wrong type(%s), looking for %s' % (self.pname, self.checktype(elt,ps), self.type), ps.Backtrace(elt)) else: #TODO: mabye change MRO to handle this debug and self.logger.debug('delegate to substitute type') what = TypeDefinition.getSubstituteType(self, elt, ps) return what.parse(elt, ps) href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Struct has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) count = len(c) if self.nilled(elt, ps): return Nilled # Create the object. v = {} # parse all attributes contained in attribute_typecode_dict (user-defined attributes), # the values (if not None) will be keyed in self.attributes dictionary. attributes = self.parse_attributes(elt, ps) if attributes: v[self.attrs_aname] = attributes #MIXED if self.mixed is True: v[self.mixed_aname] = self.simple_value(elt,ps, mixed=True) # Clone list of kids (we null it out as we process) c, crange = c[:], range(len(c)) # Loop over all items we're expecting if debug: self.logger.debug("ofwhat: %s",str(self.ofwhat)) any = None for i,what in [ (i, self.ofwhat[i]) for i in range(len(self.ofwhat)) ]: # retrieve typecode if it is hidden if callable(what): what = what() # Loop over all available kids if debug: self.logger.debug("what: (%s,%s)", what.nspname, what.pname) for j,c_elt in [ (j, c[j]) for j in crange if c[j] ]: # Parse value, and mark this one done. if debug: self.logger.debug("child node: (%s,%s)", c_elt.namespaceURI, c_elt.tagName) match = False if what.name_match(c_elt): match = True value = what.parse(c_elt, ps) else: # substitutionGroup head must be a global element declaration # if successful delegate to matching GED subwhat = _get_substitute_element(what, c_elt, ps) if subwhat: match = True value = subwhat.parse(c_elt, ps) if debug: self.logger.debug("substitutionGroup: %s", subwhat) if match: if what.maxOccurs > 1: if v.has_key(what.aname): v[what.aname].append(value) else: v[what.aname] = [value] c[j] = None continue else: v[what.aname] = value c[j] = None break if debug: self.logger.debug("no element (%s,%s)", what.nspname, what.pname) # No match; if it was supposed to be here, that's an error. if self.inorder is True and i == j: raise EvaluateException('Out of order complexType', ps.Backtrace(c_elt)) else: # only supporting 1 <any> declaration in content. if isinstance(what,AnyElement): any = what elif hasattr(what, 'default'): v[what.aname] = what.default elif what.minOccurs > 0 and not v.has_key(what.aname): raise EvaluateException('Element "' + what.aname + \ '" missing from complexType', ps.Backtrace(elt)) # Look for wildcards and unprocessed children # XXX Stick all this stuff in "any", hope for no collisions if any is not None: occurs = 0 v[any.aname] = [] for j,c_elt in [ (j, c[j]) for j in crange if c[j] ]: value = any.parse(c_elt, ps) if any.maxOccurs == UNBOUNDED or any.maxOccurs > 1: v[any.aname].append(value) else: v[any.aname] = value occurs += 1 # No such thing as nillable <any> if any.maxOccurs == 1 and occurs == 0: v[any.aname] = None elif occurs < any.minOccurs or (any.maxOccurs!=UNBOUNDED and any.maxOccurs<occurs): raise EvaluateException('occurances of <any> elements(#%d) bound by (%d,%s)' %( occurs, any.minOccurs,str(any.maxOccurs)), ps.Backtrace(elt)) if not self.pyclass: return v # type definition must be informed of element tag (nspname,pname), # element declaration is initialized with a tag. try: pyobj = self.pyclass() except Exception, e: raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \ %(self.nspname, self.pname, self.pyclass.__name__, str(e)))
def __init__( self, input, readerclass=None, keepdom=False, trailers=False, resolver=None, envelope=True, **kw ): '''Initialize. Keyword arguments: trailers -- allow trailer elments (default is zero) resolver -- function (bound method) to resolve URI's readerclass -- factory class to create a reader keepdom -- do not release the DOM envelope -- look for a SOAP envelope. ''' self.readerclass = readerclass self.keepdom = keepdom if not self.readerclass: self.readerclass = self.defaultReaderClass try: self.reader = self.readerclass() if type(input) in _stringtypes: self.dom = self.reader.fromString(input) else: self.dom = self.reader.fromStream(input) except Exception: # Is this in the header? Your guess is as good as mine. # raise ParseException("Can't parse document (" + \ # str(e.__class__) + "): " + str(e), 0) raise self.ns_cache = {id(self.dom): {'xml': XMLNS.XML, 'xmlns': XMLNS.BASE, '': ''}} (self.trailers, self.resolver, self.id_cache) = (trailers, resolver, {}) # Exactly one child element c = [E for E in _children(self.dom) if E.nodeType == _Node.ELEMENT_NODE] if len(c) == 0: raise ParseException('Document has no Envelope', 0) if len(c) != 1: raise ParseException('Document has extra child elements', 0) if envelope is False: self.body_root = c[0] return # And that one child must be the Envelope elt = c[0] if elt.localName != 'Envelope' or elt.namespaceURI not in (SOAP.ENV, SOAP.ENV12): raise ParseException('Document has %r element, not %s' % ((elt.namespaceURI, elt.localName), (SOAP.ENV12, 'Envelope')), 0) self._check_for_legal_children('Envelope', elt) for a in _attrs(elt): name = a.nodeName if name.find(':') == -1 and name not in ['xmlns', 'id']: raise ParseException('Unqualified attribute "' + name + '" in Envelope', 0) self.envelope = elt if not _valid_encoding(self.envelope): raise ParseException('Envelope has invalid encoding', 0) # Get Envelope's child elements. c = [E for E in _children(self.envelope) if E.nodeType == _Node.ELEMENT_NODE] if len(c) == 0: raise ParseException('Envelope is empty (no Body)', 0) # Envelope's first child might be the header; if so, nip it off. elt = c[0] if elt.localName == 'Header' and elt.namespaceURI in (SOAP.ENV, SOAP.ENV12): self._check_for_legal_children('Header', elt) self._check_for_pi_nodes(_children(elt), 1) self.header = c.pop(0) self.header_elements = _child_elements(self.header) else: (self.header, self.header_elements) = (None, []) # Now the first child must be the body if len(c) == 0: raise ParseException('Envelope has header but no Body', 0) elt = c.pop(0) if elt.localName != 'Body' or elt.namespaceURI not in (SOAP.ENV, SOAP.ENV12): if self.header: raise ParseException('Header followed by "%r" element, not Body' % ((elt.namespaceURI, elt.localName),), 0, elt, self.dom) else: raise ParseException('Document has "%r element, not Body' % ((elt.namespaceURI, elt.localName),), 0, elt, self.dom) self._check_for_legal_children('Body', elt, 0) self._check_for_pi_nodes(_children(elt), 0) self.body = elt if not _valid_encoding(self.body): raise ParseException('Body has invalid encoding', 0) # Trailer elements. if not self.trailers: if len(c): raise ParseException('Element found after Body', 0, elt, self.dom) else: # Don't set self.trailer_elements = []; if user didn't ask # for trailers we *want* to throw an exception. self.trailer_elements = c for elt in self.trailer_elements: if not elt.namespaceURI: raise ParseException('Unqualified trailer element', 0, elt, self.dom) # Find the serialization root. Divide the Body children into # root (root=1), no (root=0), maybe (no root attribute). (self.body_root, no, maybe) = (None, [], []) for elt in _child_elements(self.body): root = _find_root(elt) if root == '1': if self.body_root: raise ParseException('Multiple seralization roots found' , 0, elt, self.dom) self.body_root = elt elif root == '0': no.append(elt) elif not root: maybe.append(elt) else: raise ParseException('Illegal value for root attribute' , 0, elt, self.dom) # If we didn't find a root, get the first one that didn't # say "not me", unless they all said "not me." if self.body_root is None: if len(maybe): self.body_root = maybe[0] else: raise ParseException('No serialization root found', 0, self.body, self.dom) if not _valid_encoding(self.body_root): raise ParseException('Invalid encoding', 0, elt, self.dom) # Now get all the non-roots (in order!). rootid = id(self.body_root) self.data_elements = [E for E in _child_elements(self.body) if id(E) != rootid] self._check_for_pi_nodes(self.data_elements, 0)
class ParsedSoap: '''A Parsed SOAP object. Convert the text to a DOM tree and parse SOAP elements. Instance data: reader -- the DOM reader dom -- the DOM object ns_cache -- dictionary (by id(node)) of namespace dictionaries id_cache -- dictionary (by XML ID attr) of elements envelope -- the node holding the SOAP Envelope header -- the node holding the SOAP Header (or None) body -- the node holding the SOAP Body body_root -- the serialization root in the SOAP Body data_elements -- list of non-root elements in the SOAP Body trailer_elements -- list of elements following the SOAP body ''' defaultReaderClass = DefaultReader def __init__(self, input, readerclass=None, keepdom=False, trailers=False, resolver=None, envelope=True, **kw): '''Initialize. Keyword arguments: trailers -- allow trailer elments (default is zero) resolver -- function (bound method) to resolve URI's readerclass -- factory class to create a reader keepdom -- do not release the DOM envelope -- look for a SOAP envelope. ''' self.readerclass = readerclass self.keepdom = keepdom if not self.readerclass: self.readerclass = self.defaultReaderClass try: self.reader = self.readerclass() if type(input) in _stringtypes: self.dom = self.reader.fromString(input) else: self.dom = self.reader.fromStream(input) except Exception, e: # Is this in the header? Your guess is as good as mine. #raise ParseException("Can't parse document (" + \ # str(e.__class__) + "): " + str(e), 0) raise self.ns_cache = { id(self.dom): { 'xml': XMLNS.XML, 'xmlns': XMLNS.BASE, '': '' } } self.trailers, self.resolver, self.id_cache = trailers, resolver, {} # Exactly one child element c = [ E for E in _children(self.dom) if E.nodeType == _Node.ELEMENT_NODE ] if len(c) == 0: raise ParseException("Document has no Envelope", 0) if len(c) != 1: raise ParseException("Document has extra child elements", 0) if envelope is False: self.body_root = c[0] return # And that one child must be the Envelope elt = c[0] if elt.localName != "Envelope" \ or elt.namespaceURI != SOAP.ENV: raise ParseException('Document has "' + elt.localName + \ '" element, not Envelope', 0) self._check_for_legal_children("Envelope", elt) for a in _attrs(elt): name = a.nodeName if name.find(":") == -1 and name not in ["xmlns", "id"]: raise ParseException('Unqualified attribute "' + \ name + '" in Envelope', 0) self.envelope = elt if not _valid_encoding(self.envelope): raise ParseException("Envelope has invalid encoding", 0) # Get Envelope's child elements. c = [ E for E in _children(self.envelope) if E.nodeType == _Node.ELEMENT_NODE ] if len(c) == 0: raise ParseException("Envelope is empty (no Body)", 0) # Envelope's first child might be the header; if so, nip it off. elt = c[0] if elt.localName == "Header" \ and elt.namespaceURI == SOAP.ENV: self._check_for_legal_children("Header", elt) self._check_for_pi_nodes(_children(elt), 1) self.header = c.pop(0) self.header_elements = _child_elements(self.header) else: self.header, self.header_elements = None, [] # Now the first child must be the body if len(c) == 0: raise ParseException("Envelope has header but no Body", 0) elt = c.pop(0) if elt.localName != "Body" \ or elt.namespaceURI != SOAP.ENV: if self.header: raise ParseException('Header followed by "' + \ elt.localName + \ '" element, not Body', 0, elt, self.dom) else: raise ParseException('Document has "' + \ elt.localName + \ '" element, not Body', 0, elt, self.dom) self._check_for_legal_children("Body", elt, 0) self._check_for_pi_nodes(_children(elt), 0) self.body = elt if not _valid_encoding(self.body): raise ParseException("Body has invalid encoding", 0) # Trailer elements. if not self.trailers: if len(c): raise ParseException("Element found after Body", 0, elt, self.dom) # Don't set self.trailer_elements = []; if user didn't ask # for trailers we *want* to throw an exception. else: self.trailer_elements = c for elt in self.trailer_elements: if not elt.namespaceURI: raise ParseException('Unqualified trailer element', 0, elt, self.dom) # Find the serialization root. Divide the Body children into # root (root=1), no (root=0), maybe (no root attribute). self.body_root, no, maybe = None, [], [] for elt in _child_elements(self.body): root = _find_root(elt) if root == "1": if self.body_root: raise ParseException("Multiple seralization roots found", 0, elt, self.dom) self.body_root = elt elif root == "0": no.append(elt) elif not root: maybe.append(elt) else: raise ParseException('Illegal value for root attribute', 0, elt, self.dom) # If we didn't find a root, get the first one that didn't # say "not me", unless they all said "not me." if self.body_root is None: if len(maybe): self.body_root = maybe[0] else: raise ParseException('No serialization root found', 0, self.body, self.dom) if not _valid_encoding(self.body_root): raise ParseException("Invalid encoding", 0, elt, self.dom) # Now get all the non-roots (in order!). rootid = id(self.body_root) self.data_elements = [ E for E in _child_elements(self.body) if id(E) != rootid ] self._check_for_pi_nodes(self.data_elements, 0)
def parse(self, elt, ps): #if elt.localName != self.pname: # elt = elt.getElementsByTagName(self.pname)[0] self.checkname(elt, ps) if self.type and \ self.checktype(elt, ps) not in [ self.type, (None,None) ]: raise EvaluateException('Struct has wrong type', ps.Backtrace(elt)) href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Struct has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) count = len(c) if self.nilled(elt, ps): return None repeatable_args = False for tc in self.ofwhat: if tc.repeatable: repeatable_args = True break if not repeatable_args: if count > len(self.ofwhat) and not self.hasextras: raise EvaluateException('Too many sub-elements', ps.Backtrace(elt)) # Create the object. v = {} # Clone list of kids (we null it out as we process) c, crange = c[:], range(len(c)) # Loop over all items we're expecting for i,what in [ (i, self.ofwhat[i]) for i in range(len(self.ofwhat)) ]: # Loop over all available kids for j,c_elt in [ (j, c[j]) for j in crange if c[j] ]: if what.name_match(c_elt): # Parse value, and mark this one done. try: value = what.parse(c_elt, ps) except EvaluateException, e: e.str = '%s.%s: %s' % \ (self.pname or '?', what.aname or '?', e.str) raise e if what.repeatable: if v.has_key(what.aname): v[what.aname].append(value) else: v[what.aname] = [value] c[j] = None continue else: v[what.aname] = value c[j] = None break # No match; if it was supposed to be here, that's an error. if self.inorder and i == j: raise EvaluateException('Out of order struct', ps.Backtrace(c_elt)) else: if not what.optional and not v.has_key(what.aname): raise EvaluateException('Element "' + what.aname + \ '" missing from struct', ps.Backtrace(elt)) if hasattr(what, 'default'): v[what.aname] = what.default
def parse(self, elt, ps): debug = self.logger.debugOn() debug and self.logger.debug('parse') xtype = self.checkname(elt, ps) if self.type and xtype not in [self.type, (None, None)]: if not isinstance(self, TypeDefinition): raise EvaluateException(\ 'ComplexType for %s has wrong type(%s), looking for %s' % (self.pname, self.checktype(elt,ps), self.type), ps.Backtrace(elt)) else: #TODO: mabye change MRO to handle this debug and self.logger.debug('delegate to substitute type') what = TypeDefinition.getSubstituteType(self, elt, ps) return what.parse(elt, ps) href = _find_href(elt) if href: if _children(elt): raise EvaluateException('Struct has content and HREF', ps.Backtrace(elt)) elt = ps.FindLocalHREF(href, elt) c = _child_elements(elt) if self.nilled(elt, ps): return Nilled # Create the object. if self.pyclass: # type definition must be informed of element tag (nspname,pname), # element declaration is initialized with a tag. try: pyobj = self.pyclass() except Exception as e: raise TypeError("Constructing element (%s,%s) with pyclass(%s), %s" \ %(self.nspname, self.pname, self.pyclass.__name__, str(e))) else: pyobj = ComplexType._DictHolder() # parse all attributes contained in attribute_typecode_dict (user-defined attributes), # the values (if not None) will be keyed in self.attributes dictionary. attributes = self.parse_attributes(elt, ps) if attributes: setattr(pyobj, self.attrs_aname, attributes) #MIXED if self.mixed is True: setattr(pyobj, self.mixed_aname, self.simple_value(elt, ps, mixed=True)) # Clone list of kids (we null it out as we process) c, crange = c[:], list(range(len(c))) # Loop over all items we're expecting for j, c_elt in [(j, c[j]) for j in crange if c[j]]: for i, what in [(i, self.ofwhat[i]) for i in range(len(self.ofwhat))]: # retrieve typecode if it is hidden if callable(what): what = what() # Loop over all available kids # if debug: # self.logger.debug("what: (%s,%s)", what.nspname, what.pname) # Parse value, and mark this one done. # if debug: # self.logger.debug("child node: (%s,%s)", c_elt.namespaceURI, c_elt.tagName) match = False if what.name_match(c_elt): match = True value = what.parse(c_elt, ps) elif isinstance(what, AnyElement): match = True value = what.parse(c_elt, ps) else: # substitutionGroup head must be a global element declaration # if successful delegate to matching GED subwhat = _get_substitute_element(what, c_elt, ps) if subwhat: match = True value = subwhat.parse(c_elt, ps) if debug: self.logger.debug("substitutionGroup: %s", subwhat) if match: if what.maxOccurs > 1: attr = getattr(pyobj, what.aname, None) if attr is not None: attr.append(value) else: setattr(pyobj, what.aname, [value]) c[j] = None continue else: setattr(pyobj, what.aname, value) c[j] = None break if debug: self.logger.debug("no element (%s,%s)", what.nspname, what.pname) # No match; if it was supposed to be here, that's an error. if self.inorder is True and i == j: raise EvaluateException('Out of order complexType', ps.Backtrace(c_elt)) else: if hasattr(what, 'default'): setattr(pyobj, what.aname, what.default) # elif what.minOccurs > 0 and not hasattr(pyobj, what.aname): # raise EvaluateException('Element "' + what.aname + '" missing from complexType', ps.Backtrace(elt)) if isinstance(pyobj, ComplexType._DictHolder): return pyobj.__dict__ return pyobj