|
- # SOAPpy modules
- from Config import Config
- from Types import *
- from NS import NS
- from Utilities import *
-
- import string
- import fpconst
- import xml.sax
- from wstools.XMLname import fromXMLname
-
- try: from M2Crypto import SSL
- except: pass
-
- ident = '$Id: Parser.py,v 1.14 2004/01/31 04:20:05 warnes Exp $'
- from version import __version__
-
-
- ################################################################################
- # SOAP Parser
- ################################################################################
- class RefHolder:
- def __init__(self, name, frame):
- self.name = name
- self.parent = frame
- self.pos = len(frame)
- self.subpos = frame.namecounts.get(name, 0)
-
- def __repr__(self):
- return "<%s %s at %d>" % (self.__class__, self.name, id(self))
-
- def __str__(self):
- return "<%s %s at %d>" % (self.__class__, self.name, id(self))
-
- class SOAPParser(xml.sax.handler.ContentHandler):
- class Frame:
- def __init__(self, name, kind = None, attrs = {}, rules = {}):
- self.name = name
- self.kind = kind
- self.attrs = attrs
- self.rules = rules
-
- self.contents = []
- self.names = []
- self.namecounts = {}
- self.subattrs = []
-
- def append(self, name, data, attrs):
- self.names.append(name)
- self.contents.append(data)
- self.subattrs.append(attrs)
-
- if self.namecounts.has_key(name):
- self.namecounts[name] += 1
- else:
- self.namecounts[name] = 1
-
- def _placeItem(self, name, value, pos, subpos = 0, attrs = None):
- self.contents[pos] = value
-
- if attrs:
- self.attrs.update(attrs)
-
- def __len__(self):
- return len(self.contents)
-
- def __repr__(self):
- return "<%s %s at %d>" % (self.__class__, self.name, id(self))
-
- def __init__(self, rules = None):
- xml.sax.handler.ContentHandler.__init__(self)
- self.body = None
- self.header = None
- self.attrs = {}
- self._data = None
- self._next = "E" # Keeping state for message validity
- self._stack = [self.Frame('SOAP')]
-
- # Make two dictionaries to store the prefix <-> URI mappings, and
- # initialize them with the default
- self._prem = {NS.XML_T: NS.XML}
- self._prem_r = {NS.XML: NS.XML_T}
- self._ids = {}
- self._refs = {}
- self._rules = rules
-
- def startElementNS(self, name, qname, attrs):
- # Workaround two sax bugs
- if name[0] == None and name[1][0] == ' ':
- name = (None, name[1][1:])
- else:
- name = tuple(name)
-
- # First some checking of the layout of the message
-
- if self._next == "E":
- if name[1] != 'Envelope':
- raise Error, "expected `SOAP-ENV:Envelope', gto `%s:%s'" % \
- (self._prem_r[name[0]], name[1])
- if name[0] != NS.ENV:
- raise faultType, ("%s:VersionMismatch" % NS.ENV_T,
- "Don't understand version `%s' Envelope" % name[0])
- else:
- self._next = "HorB"
- elif self._next == "HorB":
- if name[0] == NS.ENV and name[1] in ("Header", "Body"):
- self._next = None
- else:
- raise Error, \
- "expected `SOAP-ENV:Header' or `SOAP-ENV:Body', " \
- "got `%s'" % self._prem_r[name[0]] + ':' + name[1]
- elif self._next == "B":
- if name == (NS.ENV, "Body"):
- self._next = None
- else:
- raise Error, "expected `SOAP-ENV:Body', got `%s'" % \
- self._prem_r[name[0]] + ':' + name[1]
- elif self._next == "":
- raise Error, "expected nothing, got `%s'" % \
- self._prem_r[name[0]] + ':' + name[1]
-
- if len(self._stack) == 2:
- rules = self._rules
- else:
- try:
- rules = self._stack[-1].rules[name[1]]
- except:
- rules = None
-
- if type(rules) not in (NoneType, DictType):
- kind = rules
- else:
- kind = attrs.get((NS.ENC, 'arrayType'))
-
- if kind != None:
- del attrs._attrs[(NS.ENC, 'arrayType')]
-
- i = kind.find(':')
- if i >= 0:
- kind = (self._prem[kind[:i]], kind[i + 1:])
- else:
- kind = None
-
- self.pushFrame(self.Frame(name[1], kind, attrs._attrs, rules))
-
- self._data = [] # Start accumulating
-
- def pushFrame(self, frame):
- self._stack.append(frame)
-
- def popFrame(self):
- return self._stack.pop()
-
- def endElementNS(self, name, qname):
- # Workaround two sax bugs
- if name[0] == None and name[1][0] == ' ':
- ns, name = None, name[1][1:]
- else:
- ns, name = tuple(name)
-
- name = fromXMLname(name) # convert to SOAP 1.2 XML name encoding
-
- if self._next == "E":
- raise Error, "didn't get SOAP-ENV:Envelope"
- if self._next in ("HorB", "B"):
- raise Error, "didn't get SOAP-ENV:Body"
-
- cur = self.popFrame()
- attrs = cur.attrs
-
- idval = None
-
- if attrs.has_key((None, 'id')):
- idval = attrs[(None, 'id')]
-
- if self._ids.has_key(idval):
- raise Error, "duplicate id `%s'" % idval
-
- del attrs[(None, 'id')]
-
- root = 1
-
- if len(self._stack) == 3:
- if attrs.has_key((NS.ENC, 'root')):
- root = int(attrs[(NS.ENC, 'root')])
-
- # Do some preliminary checks. First, if root="0" is present,
- # the element must have an id. Next, if root="n" is present,
- # n something other than 0 or 1, raise an exception.
-
- if root == 0:
- if idval == None:
- raise Error, "non-root element must have an id"
- elif root != 1:
- raise Error, "SOAP-ENC:root must be `0' or `1'"
-
- del attrs[(NS.ENC, 'root')]
-
- while 1:
- href = attrs.get((None, 'href'))
- if href:
- if href[0] != '#':
- raise Error, "Non-local hrefs are not yet suppported."
- if self._data != None and string.join(self._data, "").strip() != '':
- raise Error, "hrefs can't have data"
-
- href = href[1:]
-
- if self._ids.has_key(href):
- data = self._ids[href]
- else:
- data = RefHolder(name, self._stack[-1])
-
- if self._refs.has_key(href):
- self._refs[href].append(data)
- else:
- self._refs[href] = [data]
-
- del attrs[(None, 'href')]
-
- break
-
- kind = None
-
- if attrs:
- for i in NS.XSI_L:
- if attrs.has_key((i, 'type')):
- kind = attrs[(i, 'type')]
- del attrs[(i, 'type')]
-
- if kind != None:
- i = kind.find(':')
- if i >= 0:
- kind = (self._prem[kind[:i]], kind[i + 1:])
- else:
- # XXX What to do here? (None, kind) is just going to fail in convertType
- kind = (None, kind)
-
- null = 0
-
- if attrs:
- for i in (NS.XSI, NS.XSI2):
- if attrs.has_key((i, 'null')):
- null = attrs[(i, 'null')]
- del attrs[(i, 'null')]
-
- if attrs.has_key((NS.XSI3, 'nil')):
- null = attrs[(NS.XSI3, 'nil')]
- del attrs[(NS.XSI3, 'nil')]
-
-
- ## Check for nil
-
- # check for nil='true'
- if type(null) in (StringType, UnicodeType):
- if null.lower() == 'true':
- null = 1
-
- # check for nil=1, but watch out for string values
- try:
- null = int(null)
- except ValueError, e:
- if not e[0].startswith("invalid literal for int()"):
- raise e
- null = 0
-
- if null:
- if len(cur) or \
- (self._data != None and string.join(self._data, "").strip() != ''):
- raise Error, "nils can't have data"
-
- data = None
-
- break
-
- if len(self._stack) == 2:
- if (ns, name) == (NS.ENV, "Header"):
- self.header = data = headerType(attrs = attrs)
- self._next = "B"
- break
- elif (ns, name) == (NS.ENV, "Body"):
- self.body = data = bodyType(attrs = attrs)
- self._next = ""
- break
- elif len(self._stack) == 3 and self._next == None:
- if (ns, name) == (NS.ENV, "Fault"):
- data = faultType()
- self._next = ""
- break
-
- if cur.rules != None:
- rule = cur.rules
-
- if type(rule) in (StringType, UnicodeType):
- # XXX Need a namespace here
- rule = (None, rule)
- elif type(rule) == ListType:
- rule = tuple(rule)
-
- # XXX What if rule != kind?
- if callable(rule):
- data = rule(string.join(self._data, ""))
- elif type(rule) == DictType:
- data = structType(name = (ns, name), attrs = attrs)
- else:
- data = self.convertType(string.join(self._data, ""),
- rule, attrs)
-
- break
-
- if (kind == None and cur.kind != None) or \
- (kind == (NS.ENC, 'Array')):
- kind = cur.kind
-
- if kind == None:
- kind = 'ur-type[%d]' % len(cur)
- else:
- kind = kind[1]
-
- if len(cur.namecounts) == 1:
- elemsname = cur.names[0]
- else:
- elemsname = None
-
- data = self.startArray((ns, name), kind, attrs, elemsname)
-
- break
-
- if len(self._stack) == 3 and kind == None and \
- len(cur) == 0 and \
- (self._data == None or string.join(self._data, "").strip() == ''):
- data = structType(name = (ns, name), attrs = attrs)
- break
-
- if len(cur) == 0 and ns != NS.URN:
- # Nothing's been added to the current frame so it must be a
- # simple type.
-
- if kind == None:
- # If the current item's container is an array, it will
- # have a kind. If so, get the bit before the first [,
- # which is the type of the array, therefore the type of
- # the current item.
-
- kind = self._stack[-1].kind
-
- if kind != None:
- i = kind[1].find('[')
- if i >= 0:
- kind = (kind[0], kind[1][:i])
- elif ns != None:
- kind = (ns, name)
-
- if kind != None:
- try:
- data = self.convertType(string.join(self._data, ""),
- kind, attrs)
- except UnknownTypeError:
- data = None
- else:
- data = None
-
- if data == None:
- if self._data == None:
- data = ''
- else:
- data = string.join(self._data, "")
-
- if len(attrs) == 0:
- try: data = str(data)
- except: pass
-
- break
-
- data = structType(name = (ns, name), attrs = attrs)
-
- break
-
- if isinstance(data, compoundType):
- for i in range(len(cur)):
- v = cur.contents[i]
- data._addItem(cur.names[i], v, cur.subattrs[i])
-
- if isinstance(v, RefHolder):
- v.parent = data
-
- if root:
- self._stack[-1].append(name, data, attrs)
-
- if idval != None:
- self._ids[idval] = data
-
- if self._refs.has_key(idval):
- for i in self._refs[idval]:
- i.parent._placeItem(i.name, data, i.pos, i.subpos, attrs)
-
- del self._refs[idval]
-
- self.attrs[id(data)] = attrs
-
- if isinstance(data, anyType):
- data._setAttrs(attrs)
-
- self._data = None # Stop accumulating
-
- def endDocument(self):
- if len(self._refs) == 1:
- raise Error, \
- "unresolved reference " + self._refs.keys()[0]
- elif len(self._refs) > 1:
- raise Error, \
- "unresolved references " + ', '.join(self._refs.keys())
-
- def startPrefixMapping(self, prefix, uri):
- self._prem[prefix] = uri
- self._prem_r[uri] = prefix
-
- def endPrefixMapping(self, prefix):
- try:
- del self._prem_r[self._prem[prefix]]
- del self._prem[prefix]
- except:
- pass
-
- def characters(self, c):
- if self._data != None:
- self._data.append(c)
-
- arrayre = '^(?:(?P<ns>[^:]*):)?' \
- '(?P<type>[^[]+)' \
- '(?:\[(?P<rank>,*)\])?' \
- '(?:\[(?P<asize>\d+(?:,\d+)*)?\])$'
-
- def startArray(self, name, kind, attrs, elemsname):
- if type(self.arrayre) == StringType:
- self.arrayre = re.compile (self.arrayre)
-
- offset = attrs.get((NS.ENC, "offset"))
-
- if offset != None:
- del attrs[(NS.ENC, "offset")]
-
- try:
- if offset[0] == '[' and offset[-1] == ']':
- offset = int(offset[1:-1])
- if offset < 0:
- raise Exception
- else:
- raise Exception
- except:
- raise AttributeError, "invalid Array offset"
- else:
- offset = 0
-
- try:
- m = self.arrayre.search(kind)
-
- if m == None:
- raise Exception
-
- t = m.group('type')
-
- if t == 'ur-type':
- return arrayType(None, name, attrs, offset, m.group('rank'),
- m.group('asize'), elemsname)
- elif m.group('ns') != None:
- return typedArrayType(None, name,
- (self._prem[m.group('ns')], t), attrs, offset,
- m.group('rank'), m.group('asize'), elemsname)
- else:
- return typedArrayType(None, name, (None, t), attrs, offset,
- m.group('rank'), m.group('asize'), elemsname)
- except:
- raise AttributeError, "invalid Array type `%s'" % kind
-
- # Conversion
-
- class DATETIMECONSTS:
- SIGNre = '(?P<sign>-?)'
- CENTURYre = '(?P<century>\d{2,})'
- YEARre = '(?P<year>\d{2})'
- MONTHre = '(?P<month>\d{2})'
- DAYre = '(?P<day>\d{2})'
- HOURre = '(?P<hour>\d{2})'
- MINUTEre = '(?P<minute>\d{2})'
- SECONDre = '(?P<second>\d{2}(?:\.\d*)?)'
- TIMEZONEre = '(?P<zulu>Z)|(?P<tzsign>[-+])(?P<tzhour>\d{2}):' \
- '(?P<tzminute>\d{2})'
- BOSre = '^\s*'
- EOSre = '\s*$'
-
- __allres = {'sign': SIGNre, 'century': CENTURYre, 'year': YEARre,
- 'month': MONTHre, 'day': DAYre, 'hour': HOURre,
- 'minute': MINUTEre, 'second': SECONDre, 'timezone': TIMEZONEre,
- 'b': BOSre, 'e': EOSre}
-
- dateTime = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)sT' \
- '%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % __allres
- timeInstant = dateTime
- timePeriod = dateTime
- time = '%(b)s%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % \
- __allres
- date = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)s' \
- '(%(timezone)s)?%(e)s' % __allres
- century = '%(b)s%(sign)s%(century)s(%(timezone)s)?%(e)s' % __allres
- gYearMonth = '%(b)s%(sign)s%(century)s%(year)s-%(month)s' \
- '(%(timezone)s)?%(e)s' % __allres
- gYear = '%(b)s%(sign)s%(century)s%(year)s(%(timezone)s)?%(e)s' % \
- __allres
- year = gYear
- gMonthDay = '%(b)s--%(month)s-%(day)s(%(timezone)s)?%(e)s' % __allres
- recurringDate = gMonthDay
- gDay = '%(b)s---%(day)s(%(timezone)s)?%(e)s' % __allres
- recurringDay = gDay
- gMonth = '%(b)s--%(month)s--(%(timezone)s)?%(e)s' % __allres
- month = gMonth
-
- recurringInstant = '%(b)s%(sign)s(%(century)s|-)(%(year)s|-)-' \
- '(%(month)s|-)-(%(day)s|-)T' \
- '(%(hour)s|-):(%(minute)s|-):(%(second)s|-)' \
- '(%(timezone)s)?%(e)s' % __allres
-
- duration = '%(b)s%(sign)sP' \
- '((?P<year>\d+)Y)?' \
- '((?P<month>\d+)M)?' \
- '((?P<day>\d+)D)?' \
- '((?P<sep>T)' \
- '((?P<hour>\d+)H)?' \
- '((?P<minute>\d+)M)?' \
- '((?P<second>\d*(?:\.\d*)?)S)?)?%(e)s' % \
- __allres
-
- timeDuration = duration
-
- # The extra 31 on the front is:
- # - so the tuple is 1-based
- # - so months[month-1] is December's days if month is 1
-
- months = (31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
-
- def convertDateTime(self, value, kind):
- def getZoneOffset(d):
- zoffs = 0
-
- try:
- if d['zulu'] == None:
- zoffs = 60 * int(d['tzhour']) + int(d['tzminute'])
- if d['tzsign'] != '-':
- zoffs = -zoffs
- except TypeError:
- pass
-
- return zoffs
-
- def applyZoneOffset(months, zoffs, date, minfield, posday = 1):
- if zoffs == 0 and (minfield > 4 or 0 <= date[5] < 60):
- return date
-
- if minfield > 5: date[5] = 0
- if minfield > 4: date[4] = 0
-
- if date[5] < 0:
- date[4] += int(date[5]) / 60
- date[5] %= 60
-
- date[4] += zoffs
-
- if minfield > 3 or 0 <= date[4] < 60: return date
-
- date[3] += date[4] / 60
- date[4] %= 60
-
- if minfield > 2 or 0 <= date[3] < 24: return date
-
- date[2] += date[3] / 24
- date[3] %= 24
-
- if minfield > 1:
- if posday and date[2] <= 0:
- date[2] += 31 # zoffs is at most 99:59, so the
- # day will never be less than -3
- return date
-
- while 1:
- # The date[1] == 3 (instead of == 2) is because we're
- # going back a month, so we need to know if the previous
- # month is February, so we test if this month is March.
-
- leap = minfield == 0 and date[1] == 3 and \
- date[0] % 4 == 0 and \
- (date[0] % 100 != 0 or date[0] % 400 == 0)
-
- if 0 < date[2] <= months[date[1]] + leap: break
-
- date[2] += months[date[1] - 1] + leap
-
- date[1] -= 1
-
- if date[1] > 0: break
-
- date[1] = 12
-
- if minfield > 0: break
-
- date[0] -= 1
-
- return date
-
- try:
- exp = getattr(self.DATETIMECONSTS, kind)
- except AttributeError:
- return None
-
- if type(exp) == StringType:
- exp = re.compile(exp)
- setattr (self.DATETIMECONSTS, kind, exp)
-
- m = exp.search(value)
-
- try:
- if m == None:
- raise Exception
-
- d = m.groupdict()
- f = ('century', 'year', 'month', 'day',
- 'hour', 'minute', 'second')
- fn = len(f) # Index of first non-None value
- r = []
-
- if kind in ('duration', 'timeDuration'):
- if d['sep'] != None and d['hour'] == None and \
- d['minute'] == None and d['second'] == None:
- raise Exception
-
- f = f[1:]
-
- for i in range(len(f)):
- s = d[f[i]]
-
- if s != None:
- if f[i] == 'second':
- s = float(s)
- else:
- try: s = int(s)
- except ValueError: s = long(s)
-
- if i < fn: fn = i
-
- r.append(s)
-
- if fn > len(r): # Any non-Nones?
- raise Exception
-
- if d['sign'] == '-':
- r[fn] = -r[fn]
-
- return tuple(r)
-
- if kind == 'recurringInstant':
- for i in range(len(f)):
- s = d[f[i]]
-
- if s == None or s == '-':
- if i > fn:
- raise Exception
- s = None
- else:
- if i < fn:
- fn = i
-
- if f[i] == 'second':
- s = float(s)
- else:
- try:
- s = int(s)
- except ValueError:
- s = long(s)
-
- r.append(s)
-
- s = r.pop(0)
-
- if fn == 0:
- r[0] += s * 100
- else:
- fn -= 1
-
- if fn < len(r) and d['sign'] == '-':
- r[fn] = -r[fn]
-
- cleanDate(r, fn)
-
- return tuple(applyZoneOffset(self.DATETIMECONSTS.months,
- getZoneOffset(d), r, fn, 0))
-
- r = [0, 0, 1, 1, 0, 0, 0]
-
- for i in range(len(f)):
- field = f[i]
-
- s = d.get(field)
-
- if s != None:
- if field == 'second':
- s = float(s)
- else:
- try:
- s = int(s)
- except ValueError:
- s = long(s)
-
- if i < fn:
- fn = i
-
- r[i] = s
-
- if fn > len(r): # Any non-Nones?
- raise Exception
-
- s = r.pop(0)
-
- if fn == 0:
- r[0] += s * 100
- else:
- fn -= 1
-
- if d.get('sign') == '-':
- r[fn] = -r[fn]
-
- cleanDate(r, fn)
-
- zoffs = getZoneOffset(d)
-
- if zoffs:
- r = applyZoneOffset(self.DATETIMECONSTS.months, zoffs, r, fn)
-
- if kind == 'century':
- return r[0] / 100
-
- s = []
-
- for i in range(1, len(f)):
- if d.has_key(f[i]):
- s.append(r[i - 1])
-
- if len(s) == 1:
- return s[0]
- return tuple(s)
- except Exception, e:
- raise Error, "invalid %s value `%s' - %s" % (kind, value, e)
-
- intlimits = \
- {
- 'nonPositiveInteger': (0, None, 0),
- 'non-positive-integer': (0, None, 0),
- 'negativeInteger': (0, None, -1),
- 'negative-integer': (0, None, -1),
- 'long': (1, -9223372036854775808L,
- 9223372036854775807L),
- 'int': (0, -2147483648L, 2147483647),
- 'short': (0, -32768, 32767),
- 'byte': (0, -128, 127),
- 'nonNegativeInteger': (0, 0, None),
- 'non-negative-integer': (0, 0, None),
- 'positiveInteger': (0, 1, None),
- 'positive-integer': (0, 1, None),
- 'unsignedLong': (1, 0, 18446744073709551615L),
- 'unsignedInt': (0, 0, 4294967295L),
- 'unsignedShort': (0, 0, 65535),
- 'unsignedByte': (0, 0, 255),
- }
- floatlimits = \
- {
- 'float': (7.0064923216240861E-46, -3.4028234663852886E+38,
- 3.4028234663852886E+38),
- 'double': (2.4703282292062327E-324, -1.7976931348623158E+308,
- 1.7976931348623157E+308),
- }
- zerofloatre = '[1-9]'
-
-
-
-
-
- def convertType(self, d, t, attrs, config=Config):
- return self.convertToBasicTypes(d, t, attrs, config)
-
-
- def convertToSOAPpyTypes(self, d, t, attrs, config=Config):
- pass
-
-
- def convertToBasicTypes(self, d, t, attrs, config=Config):
- dnn = d or ''
-
- if t[0] in NS.EXSD_L:
- if t[1] == "integer":
- try:
- d = int(d)
- if len(attrs):
- d = long(d)
- except:
- d = long(d)
- return d
- if self.intlimits.has_key (t[1]): # integer types
- l = self.intlimits[t[1]]
- try: d = int(d)
- except: d = long(d)
-
- if l[1] != None and d < l[1]:
- raise UnderflowError, "%s too small" % d
- if l[2] != None and d > l[2]:
- raise OverflowError, "%s too large" % d
-
- if l[0] or len(attrs):
- return long(d)
- return d
- if t[1] == "string":
- if len(attrs):
- return unicode(dnn)
- try:
- return str(dnn)
- except:
- return dnn
- if t[1] == "boolean":
- d = d.strip().lower()
- if d in ('0', 'false'):
- return 0
- if d in ('1', 'true'):
- return 1
- raise AttributeError, "invalid boolean value"
- if t[1] in ('double','float'):
- l = self.floatlimits[t[1]]
- s = d.strip().lower()
-
- d = float(s)
-
- if config.strict_range:
- if d < l[1]: raise UnderflowError
- if d > l[2]: raise OverflowError
- else:
- # some older SOAP impementations (notably SOAP4J,
- # Apache SOAP) return "infinity" instead of "INF"
- # so check the first 3 characters for a match.
- if s == "nan":
- return fpconst.NaN
- elif s[0:3] in ("inf", "+inf"):
- return fpconst.PosInf
- elif s[0:3] == "-inf":
- return fpconst.NegInf
-
- if fpconst.isNaN(d):
- if s != 'nan':
- raise ValueError, "invalid %s: %s" % (t[1], s)
- elif fpconst.isNegInf(d):
- if s != '-inf':
- raise UnderflowError, "%s too small: %s" % (t[1], s)
- elif fpconst.isPosInf(d):
- if s != 'inf':
- raise OverflowError, "%s too large: %s" % (t[1], s)
- elif d < 0 and d < l[1]:
- raise UnderflowError, "%s too small: %s" % (t[1], s)
- elif d > 0 and ( d < l[0] or d > l[2] ):
- raise OverflowError, "%s too large: %s" % (t[1], s)
- elif d == 0:
- if type(self.zerofloatre) == StringType:
- self.zerofloatre = re.compile(self.zerofloatre)
-
- if self.zerofloatre.search(s):
- raise UnderflowError, "invalid %s: %s" % (t[1], s)
-
- return d
- if t[1] in ("dateTime", "date", "timeInstant", "time"):
- return self.convertDateTime(d, t[1])
- if t[1] == "decimal":
- return float(d)
- if t[1] in ("language", "QName", "NOTATION", "NMTOKEN", "Name",
- "NCName", "ID", "IDREF", "ENTITY"):
- return collapseWhiteSpace(d)
- if t[1] in ("IDREFS", "ENTITIES", "NMTOKENS"):
- d = collapseWhiteSpace(d)
- return d.split()
- if t[0] in NS.XSD_L:
- if t[1] in ("base64", "base64Binary"):
- if d:
- return base64.decodestring(d)
- else:
- return ''
- if t[1] == "hexBinary":
- if d:
- return decodeHexString(d)
- else:
- return
- if t[1] == "anyURI":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] in ("normalizedString", "token"):
- return collapseWhiteSpace(d)
- if t[0] == NS.ENC:
- if t[1] == "base64":
- if d:
- return base64.decodestring(d)
- else:
- return ''
- if t[0] == NS.XSD:
- if t[1] == "binary":
- try:
- e = attrs[(None, 'encoding')]
-
- if d:
- if e == 'hex':
- return decodeHexString(d)
- elif e == 'base64':
- return base64.decodestring(d)
- else:
- return ''
- except:
- pass
-
- raise Error, "unknown or missing binary encoding"
- if t[1] == "uri":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] == "recurringInstant":
- return self.convertDateTime(d, t[1])
- if t[0] in (NS.XSD2, NS.ENC):
- if t[1] == "uriReference":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] == "timePeriod":
- return self.convertDateTime(d, t[1])
- if t[1] in ("century", "year"):
- return self.convertDateTime(d, t[1])
- if t[0] in (NS.XSD, NS.XSD2, NS.ENC):
- if t[1] == "timeDuration":
- return self.convertDateTime(d, t[1])
- if t[0] == NS.XSD3:
- if t[1] == "anyURI":
- return urllib.unquote(collapseWhiteSpace(d))
- if t[1] in ("gYearMonth", "gMonthDay"):
- return self.convertDateTime(d, t[1])
- if t[1] == "gYear":
- return self.convertDateTime(d, t[1])
- if t[1] == "gMonth":
- return self.convertDateTime(d, t[1])
- if t[1] == "gDay":
- return self.convertDateTime(d, t[1])
- if t[1] == "duration":
- return self.convertDateTime(d, t[1])
- if t[0] in (NS.XSD2, NS.XSD3):
- if t[1] == "token":
- return collapseWhiteSpace(d)
- if t[1] == "recurringDate":
- return self.convertDateTime(d, t[1])
- if t[1] == "month":
- return self.convertDateTime(d, t[1])
- if t[1] == "recurringDay":
- return self.convertDateTime(d, t[1])
- if t[0] == NS.XSD2:
- if t[1] == "CDATA":
- return collapseWhiteSpace(d)
-
- raise UnknownTypeError, "unknown type `%s'" % (t[0] + ':' + t[1])
-
-
- ################################################################################
- # call to SOAPParser that keeps all of the info
- ################################################################################
- def _parseSOAP(xml_str, rules = None):
- try:
- from cStringIO import StringIO
- except ImportError:
- from StringIO import StringIO
-
- parser = xml.sax.make_parser()
- t = SOAPParser(rules = rules)
- parser.setContentHandler(t)
- e = xml.sax.handler.ErrorHandler()
- parser.setErrorHandler(e)
-
- inpsrc = xml.sax.xmlreader.InputSource()
- inpsrc.setByteStream(StringIO(xml_str))
-
- # turn on namespace mangeling
- parser.setFeature(xml.sax.handler.feature_namespaces,1)
-
- try:
- parser.parse(inpsrc)
- except xml.sax.SAXParseException, e:
- parser._parser = None
- raise e
-
- return t
-
- ################################################################################
- # SOAPParser's more public interface
- ################################################################################
- def parseSOAP(xml_str, attrs = 0):
- t = _parseSOAP(xml_str)
-
- if attrs:
- return t.body, t.attrs
- return t.body
-
-
- def parseSOAPRPC(xml_str, header = 0, body = 0, attrs = 0, rules = None):
- #config=Config, unwrap_outer=1):
-
- t = _parseSOAP(xml_str, rules = rules)
- p = t.body[0]
-
- # Empty string, for RPC this translates into a void
- if type(p) in (type(''), type(u'')) and p in ('', u''):
- name = "Response"
- for k in t.body.__dict__.keys():
- if k[0] != "_":
- name = k
- p = structType(name)
-
- if header or body or attrs:
- ret = (p,)
- if header : ret += (t.header,)
- if body: ret += (t.body,)
- if attrs: ret += (t.attrs,)
- return ret
- else:
- return p
|