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 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 FindLocalHREF(self, href, elt, headers=1): """Find a local HREF in the data elements. """ if href[0] != "#": raise EvaluateException('Absolute HREF ("%s") not implemented' % href, self.Backtrace(elt)) frag = href[1:] # Already found? e = self.id_cache.get(frag) if e: return e # Do a breadth-first search, in the data first. Most likely # to find multi-ref targets shallow in the data area. list = self.data_elements[:] + [self.body_root] if headers: list.extend(self.header_elements) while list: e = list.pop() if e.nodeType == _Node.ELEMENT_NODE: nodeid = _find_id(e) if nodeid: self.id_cache[nodeid] = e if nodeid == frag: return e list += _children(e) raise EvaluateException('''Can't find node for HREF "%s"''' % href, self.Backtrace(elt))
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 FindLocalHREF(self, href, elt, headers=1): '''Find a local HREF in the data elements. ''' if href[0] != '#': raise EvaluateException( 'Absolute HREF ("%s") not implemented' % href, self.Backtrace(elt)) frag = href[1:] # Already found? e = self.id_cache.get(frag) if e: return e # Do a breadth-first search, in the data first. Most likely # to find multi-ref targets shallow in the data area. list = self.data_elements[:] + [self.body_root] if headers: list.extend(self.header_elements) while list: e = list.pop() if e.nodeType == _Node.ELEMENT_NODE: nodeid = _find_id(e) if nodeid: self.id_cache[nodeid] = e if nodeid == frag: return e list += _children(e) raise EvaluateException('''Can't find node for HREF "%s"''' % href, self.Backtrace(elt))
def SimpleHREF(self, elt, ps, tag): '''Simple HREF for non-string and non-struct and non-array. ''' if len(_children(elt)): return elt href = _find_href(elt) if not href: if self.optional: return None raise EvaluateException('Non-optional ' + tag + ' missing', ps.Backtrace(elt)) return ps.FindLocalHREF(href, elt, 0)
def parse(self, elt, ps): self.checkname(elt, ps) if len(_children(elt)) == 0: href = _find_href(elt) if not href: if _find_nil(elt) not in [ "true", "1"]: # No content, no HREF, not NIL: empty string return "" # No content, no HREF, and is NIL... if self.optional: return None raise EvaluateException('Non-optional string missing', ps.Backtrace(elt)) if href[0] != '#': return ps.ResolveHREF(href, self) elt = ps.FindLocalHREF(href, elt) self.checktype(elt, ps) if self.nilled(elt, ps): return None if len(_children(elt)) == 0: return '' v = self.simple_value(elt, ps) if self.strip: v = v.strip() return v
def _check_for_pi_nodes(self, list, inheader): """Raise an exception if any of the list descendants are PI nodes. """ list = list[:] while list: elt = list.pop() t = elt.nodeType if t == _Node.PROCESSING_INSTRUCTION_NODE: raise ParseException( 'Found processing instruction "<?' + elt.nodeName + '...>"', inheader, elt.parentNode, self.dom ) elif t == _Node.DOCUMENT_TYPE_NODE: raise ParseException("Found DTD", inheader, elt.parentNode, self.dom) list += _children(elt)
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 _check_for_pi_nodes(self, list, inheader): '''Raise an exception if any of the list descendants are PI nodes. ''' list = list[:] while list: elt = list.pop() t = elt.nodeType if t == _Node.PROCESSING_INSTRUCTION_NODE: raise ParseException('Found processing instruction "<?' + \ elt.nodeName + '...>"', inheader, elt.parentNode, self.dom) elif t == _Node.DOCUMENT_TYPE_NODE: raise ParseException('Found DTD', inheader, elt.parentNode, self.dom) list += _children(elt)
def _check_for_legal_children(self, name, elt, mustqualify=1): """Check if all children of this node are elements or whitespace-only text nodes. """ inheader = name == "Header" for n in _children(elt): t = n.nodeType if t == _Node.COMMENT_NODE: continue if t != _Node.ELEMENT_NODE: if t == _Node.TEXT_NODE and n.nodeValue.strip() == "": continue raise ParseException("Non-element child in " + name, inheader, elt, self.dom) if mustqualify and not n.namespaceURI: raise ParseException('Unqualified element "' + n.nodeName + '" in ' + name, inheader, elt, self.dom)
def _check_for_legal_children(self, name, elt, mustqualify=1): '''Check if all children of this node are elements or whitespace-only text nodes. ''' inheader = name == "Header" for n in _children(elt): t = n.nodeType if t == _Node.COMMENT_NODE: continue if t != _Node.ELEMENT_NODE: if t == _Node.TEXT_NODE and n.nodeValue.strip() == "": continue raise ParseException("Non-element child in " + name, inheader, elt, self.dom) if mustqualify and not n.namespaceURI: raise ParseException('Unqualified element "' + \ n.nodeName + '" in ' + name, inheader, elt, self.dom)
def simple_value(self, elt, ps): '''Get the value of the simple content of this element. ''' if not _valid_encoding(elt): raise EvaluateException('Invalid encoding', ps.Backtrace(elt)) c = _children(elt) if len(c) == 0: raise EvaluateException('Value missing', ps.Backtrace(elt)) for c_elt in c: if c_elt.nodeType == _Node.ELEMENT_NODE: raise EvaluateException('Sub-elements in value', ps.Backtrace(c_elt)) # It *seems* to be consensus that ignoring comments and # concatenating the text nodes is the right thing to do. return ''.join([E.nodeValue for E in c if E.nodeType in [ _Node.TEXT_NODE, _Node.CDATA_SECTION_NODE ]])
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 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 parse(self, elt, ps): self.checkname(elt, ps) if len(_children(elt)): raise EvaluateException('Void got a value', ps.Backtrace(elt)) return None
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 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 __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)
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 _do_element(self, node, initial_other_attrs = []): '''_do_element(self, node, initial_other_attrs = []) -> None Process an element (and its children).''' # Get state (from the stack) make local copies. # ns_parent -- NS declarations in parent # ns_rendered -- NS nodes rendered by ancestors # xml_attrs -- Attributes in XML namespace from parent # ns_local -- NS declarations relevant to this element ns_parent, ns_rendered, xml_attrs = \ self.state[0], self.state[1][:], self.state[2][:] ns_local = ns_parent.copy() # Divide attributes into NS, XML, and others. other_attrs = initial_other_attrs[:] in_subset = _in_subset(self.subset, node) for a in _attrs(node): if a.namespaceURI == XMLNS.BASE: n = a.nodeName if n == "xmlns:": n = "xmlns" # DOM bug workaround ns_local[n] = a.nodeValue elif a.namespaceURI == XMLNS.XML: if self.unsuppressedPrefixes is None or in_subset: xml_attrs.append(a) else: other_attrs.append(a) # Render the node W, name = self.write, None if in_subset: name = node.nodeName W('<') W(name) # Create list of NS attributes to render. ns_to_render = [] for n,v in ns_local.items(): pval = ns_parent.get(n) # If default namespace is XMLNS.BASE or empty, skip if n == "xmlns" \ and v in [ XMLNS.BASE, '' ] and pval in [ XMLNS.BASE, '' ]: continue # "omit namespace node with local name xml, which defines # the xml prefix, if its string value is # http://www.w3.org/XML/1998/namespace." if n == "xmlns:xml" \ and v in [ 'http://www.w3.org/XML/1998/namespace' ]: continue # If different from parent, or parent didn't render # and if not exclusive, or this prefix is needed or # not suppressed if (v != pval or n not in ns_rendered) \ and (self.unsuppressedPrefixes is None or \ _utilized(n, node, other_attrs, self.unsuppressedPrefixes)): ns_to_render.append((n, v)) # Sort and render the ns, marking what was rendered. ns_to_render.sort(_sorter_ns) for n,v in ns_to_render: self._do_attr(n, v) ns_rendered.append(n) # Add in the XML attributes (don't pass to children, since # we're rendering them), sort, and render. other_attrs.extend(xml_attrs) xml_attrs = [] other_attrs.sort(_sorter) for a in other_attrs: self._do_attr(a.nodeName, a.value) W('>') # Push state, recurse, pop state. state, self.state = self.state, (ns_local, ns_rendered, xml_attrs) for c in _children(node): _implementation.handlers[c.nodeType](self, c) self.state = state if name: W('</%s>' % name)
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)
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