00001
00002
00003 '''General typecodes.
00004 '''
00005
00006 from ZSI import _copyright, _children, _child_elements, \
00007 _floattypes, _stringtypes, _seqtypes, _find_attr, _find_attrNS, _find_attrNodeNS, \
00008 _find_arraytype, _find_default_namespace, _find_href, _find_encstyle, \
00009 _resolve_prefix, _find_xsi_attr, _find_type, \
00010 _find_xmlns_prefix, _get_element_nsuri_name, _get_idstr, \
00011 _Node, EvaluateException, UNICODE_ENCODING, \
00012 _valid_encoding, ParseException
00013
00014 from ZSI.wstools.Namespaces import SCHEMA, SOAP
00015 from ZSI.wstools.Utility import SplitQName
00016 from ZSI.wstools.c14n import Canonicalize
00017 from ZSI.wstools.logging import getLogger as _GetLogger
00018
00019 import re, types, time, copy
00020
00021 from base64 import decodestring as b64decode, encodestring as b64encode
00022 from urllib import unquote as urldecode, quote as urlencode
00023 from binascii import unhexlify as hexdecode, hexlify as hexencode
00024 try:
00025 from cStringIO import StringIO
00026 except ImportError:
00027 from StringIO import StringIO
00028
00029
00030 _is_xsd_or_soap_ns = lambda ns: ns in [
00031 SCHEMA.XSD3, SOAP.ENC, SCHEMA.XSD1, SCHEMA.XSD2, ]
00032 _find_nil = lambda E: _find_xsi_attr(E, "null") or _find_xsi_attr(E, "nil")
00033
00034 def _get_xsitype(pyclass):
00035 '''returns the xsi:type as a tuple, coupled with ZSI.schema
00036 '''
00037 if hasattr(pyclass,'type') and type(pyclass.type) in _seqtypes:
00038 return pyclass.type
00039 elif hasattr(pyclass,'type') and hasattr(pyclass, 'schema'):
00040 return (pyclass.schema, pyclass.type)
00041
00042 return (None,None)
00043
00044
00045
00046 Nilled = None
00047 UNBOUNDED = 'unbounded'
00048
00049
00050 class TypeCode:
00051 '''The parent class for all parseable SOAP types.
00052 Class data:
00053 typechecks -- do init-time type checking if non-zero
00054 Class data subclasses may define:
00055 tag -- global element declaration
00056 type -- global type definition
00057 parselist -- list of valid SOAP types for this class, as
00058 (uri,name) tuples, where a uri of None means "all the XML
00059 Schema namespaces"
00060 errorlist -- parselist in a human-readable form; will be
00061 generated if/when needed
00062 seriallist -- list of Python types or user-defined classes
00063 that this typecode can serialize.
00064 logger -- logger instance for this class.
00065 '''
00066 tag = None
00067 type = (None,None)
00068 typechecks = True
00069 attribute_typecode_dict = None
00070 logger = _GetLogger('ZSI.TC.TypeCode')
00071
00072 def __init__(self, pname=None, aname=None, minOccurs=1,
00073 maxOccurs=1, nillable=False, typed=True, unique=True,
00074 pyclass=None, attrs_aname='_attrs', **kw):
00075 '''Baseclass initialization.
00076 Instance data (and usually keyword arg)
00077 pname -- the parameter name (localname).
00078 nspname -- the namespace for the parameter;
00079 None to ignore the namespace
00080 typed -- output xsi:type attribute
00081 unique -- data item is not aliased (no href/id needed)
00082 minOccurs -- min occurances
00083 maxOccurs -- max occurances
00084 nillable -- is item nillable?
00085 attrs_aname -- This is variable name to dictionary of attributes
00086 encoded -- encoded namespaceURI (specify if use is encoded)
00087 '''
00088 if type(pname) in _seqtypes:
00089 self.nspname, self.pname = pname
00090 else:
00091 self.nspname, self.pname = None, pname
00092
00093 if self.pname:
00094 self.pname = str(self.pname).split(':')[-1]
00095
00096 self.aname = aname or self.pname
00097 self.minOccurs = minOccurs
00098 self.maxOccurs = maxOccurs
00099 self.nillable = nillable
00100 self.typed = typed
00101 self.unique = unique
00102 self.attrs_aname = attrs_aname
00103 self.pyclass = pyclass
00104
00105
00106 encoded = kw.get('encoded')
00107 if encoded is not None:
00108 self.nspname = kw['encoded']
00109
00110 def parse(self, elt, ps):
00111 '''
00112 Parameters:
00113 elt -- the DOM element being parsed
00114 ps -- the ParsedSoap object.
00115 '''
00116 raise EvaluateException("Unimplemented evaluation", ps.Backtrace(elt))
00117
00118 def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
00119 '''
00120 Parameters:
00121 elt -- the current DOMWrapper element
00122 sw -- soapWriter object
00123 pyobj -- python object to serialize
00124
00125 '''
00126 raise EvaluateException("Unimplemented evaluation", sw.Backtrace(elt))
00127
00128 def text_to_data(self, text, elt, ps):
00129 '''convert text into typecode specific data.
00130 Parameters:
00131 text -- text content
00132 elt -- the DOM element being parsed
00133 ps -- the ParsedSoap object.
00134 '''
00135 raise EvaluateException("Unimplemented evaluation", ps.Backtrace(elt))
00136
00137 def serialize_as_nil(self, elt):
00138 '''
00139 Parameters:
00140 elt -- the current DOMWrapper element
00141 '''
00142 elt.setAttributeNS(SCHEMA.XSI3, 'nil', '1')
00143
00144 def SimpleHREF(self, elt, ps, tag):
00145 '''Simple HREF for non-string and non-struct and non-array.
00146 Parameters:
00147 elt -- the DOM element being parsed
00148 ps -- the ParsedSoap object.
00149 tag --
00150 '''
00151 if len(_children(elt)): return elt
00152 href = _find_href(elt)
00153 if not href:
00154 if self.minOccurs is 0: return None
00155 raise EvaluateException('Required' + tag + ' missing',
00156 ps.Backtrace(elt))
00157 return ps.FindLocalHREF(href, elt, 0)
00158
00159 def get_parse_and_errorlist(self):
00160 """Get the parselist and human-readable version, errorlist is returned,
00161 because it is used in error messages.
00162 """
00163 d = self.__class__.__dict__
00164 parselist = d.get('parselist')
00165 errorlist = d.get('errorlist')
00166 if parselist and not errorlist:
00167 errorlist = []
00168 for t in parselist:
00169 if t[1] not in errorlist: errorlist.append(t[1])
00170 errorlist = ' or '.join(errorlist)
00171 d['errorlist'] = errorlist
00172 return (parselist, errorlist)
00173
00174 def checkname(self, elt, ps):
00175 '''See if the name and type of the "elt" element is what we're
00176 looking for. Return the element's type.
00177 Parameters:
00178 elt -- the DOM element being parsed
00179 ps -- the ParsedSoap object.
00180 '''
00181
00182 parselist,errorlist = self.get_parse_and_errorlist()
00183 ns, name = _get_element_nsuri_name(elt)
00184 if ns == SOAP.ENC:
00185
00186 if parselist and \
00187 (None, name) not in parselist and (ns, name) not in parselist:
00188 raise EvaluateException(
00189 'Element mismatch (got %s wanted %s) (SOAP encoding namespace)' % \
00190 (name, errorlist), ps.Backtrace(elt))
00191 return (ns, name)
00192
00193
00194 if self.nspname and ns != self.nspname:
00195 raise EvaluateException('Element NS mismatch (got %s wanted %s)' % \
00196 (ns, self.nspname), ps.Backtrace(elt))
00197
00198 if self.pname and name != self.pname:
00199 raise EvaluateException('Element Name mismatch (got %s wanted %s)' % \
00200 (name, self.pname), ps.Backtrace(elt))
00201 return self.checktype(elt, ps)
00202
00203 def checktype(self, elt, ps):
00204 '''See if the type of the "elt" element is what we're looking for.
00205 Return the element's type.
00206 Parameters:
00207 elt -- the DOM element being parsed
00208 ps -- the ParsedSoap object.
00209 '''
00210 typeName = _find_type(elt)
00211 if typeName is None or typeName == "":
00212 return (None,None)
00213
00214
00215 prefix,typeName = SplitQName(typeName)
00216 uri = ps.GetElementNSdict(elt).get(prefix)
00217 if uri is None:
00218 raise EvaluateException('Malformed type attribute (bad NS)',
00219 ps.Backtrace(elt))
00220
00221
00222 parselist,errorlist = self.get_parse_and_errorlist()
00223 if not parselist or \
00224 (uri,typeName) in parselist or \
00225 (_is_xsd_or_soap_ns(uri) and (None,typeName) in parselist):
00226 return (uri,typeName)
00227 raise EvaluateException(
00228 'Type mismatch (%s namespace) (got %s wanted %s)' % \
00229 (uri, typeName, errorlist), ps.Backtrace(elt))
00230
00231 def name_match(self, elt):
00232 '''Simple boolean test to see if we match the element name.
00233 Parameters:
00234 elt -- the DOM element being parsed
00235 '''
00236 return self.pname == elt.localName and \
00237 self.nspname in [None, '', elt.namespaceURI]
00238
00239 def nilled(self, elt, ps):
00240 '''Is the element NIL, and is that okay?
00241 Parameters:
00242 elt -- the DOM element being parsed
00243 ps -- the ParsedSoap object.
00244 '''
00245 if _find_nil(elt) not in [ "true", "1"]: return False
00246 if self.nillable is False:
00247 raise EvaluateException('Non-nillable element is NIL',
00248 ps.Backtrace(elt))
00249 return True
00250
00251 def simple_value(self, elt, ps, mixed=False):
00252 '''Get the value of the simple content of this element.
00253 Parameters:
00254 elt -- the DOM element being parsed
00255 ps -- the ParsedSoap object.
00256 mixed -- ignore element content, optional text node
00257 '''
00258 if not _valid_encoding(elt):
00259 raise EvaluateException('Invalid encoding', ps.Backtrace(elt))
00260 c = _children(elt)
00261 if mixed is False:
00262 if len(c) == 0:
00263 raise EvaluateException('Value missing', ps.Backtrace(elt))
00264 for c_elt in c:
00265 if c_elt.nodeType == _Node.ELEMENT_NODE:
00266 raise EvaluateException('Sub-elements in value',
00267 ps.Backtrace(c_elt))
00268
00269
00270
00271 return ''.join([E.nodeValue for E in c
00272 if E.nodeType
00273 in [ _Node.TEXT_NODE, _Node.CDATA_SECTION_NODE ]])
00274
00275 def parse_attributes(self, elt, ps):
00276 '''find all attributes specified in the attribute_typecode_dict in
00277 current element tag, if an attribute is found set it in the
00278 self.attributes dictionary. Default to putting in String.
00279 Parameters:
00280 elt -- the DOM element being parsed
00281 ps -- the ParsedSoap object.
00282 '''
00283 if self.attribute_typecode_dict is None:
00284 return
00285
00286 attributes = {}
00287 for attr,what in self.attribute_typecode_dict.items():
00288 namespaceURI,localName = None,attr
00289 if type(attr) in _seqtypes:
00290 namespaceURI,localName = attr
00291 value = _find_attrNodeNS(elt, namespaceURI, localName)
00292 self.logger.debug("Parsed Attribute (%s,%s) -- %s",
00293 namespaceURI, localName, value)
00294
00295
00296 if value is None: continue
00297 attributes[attr] = what.text_to_data(value, elt, ps)
00298
00299 return attributes
00300
00301 def set_attributes(self, el, pyobj):
00302 '''Instance data attributes contains a dictionary
00303 of keys (namespaceURI,localName) and attribute values.
00304 These values can be self-describing (typecode), or use
00305 attribute_typecode_dict to determine serialization.
00306 Paramters:
00307 el -- MessageInterface representing the element
00308 pyobj --
00309 '''
00310 if not hasattr(pyobj, self.attrs_aname):
00311 return
00312
00313 if not isinstance(getattr(pyobj, self.attrs_aname), dict):
00314 raise TypeError,\
00315 'pyobj.%s must be a dictionary of names and values'\
00316 % self.attrs_aname
00317
00318 for attr, value in getattr(pyobj, self.attrs_aname).items():
00319 namespaceURI,localName = None, attr
00320 if type(attr) in _seqtypes:
00321 namespaceURI, localName = attr
00322
00323 what = None
00324 if getattr(self, 'attribute_typecode_dict', None) is not None:
00325 what = self.attribute_typecode_dict.get(attr)
00326 if what is None and namespaceURI is None:
00327 what = self.attribute_typecode_dict.get(localName)
00328
00329
00330 if hasattr(value, 'typecode') and not isinstance(what, AnyType):
00331 if what is not None and not isinstance(value.typecode, what):
00332 raise EvaluateException, \
00333 'self-describing attribute must subclass %s'\
00334 %what.__class__
00335
00336 what = value.typecode
00337
00338 self.logger.debug("attribute create -- %s", value)
00339 if isinstance(what, QName):
00340 what.set_prefix(el, value)
00341
00342
00343 if what is None:
00344 value = str(value)
00345 else:
00346 value = what.get_formatted_content(value)
00347
00348 el.setAttributeNS(namespaceURI, localName, value)
00349
00350 def set_attribute_xsi_type(self, el, **kw):
00351 '''if typed, set the xsi:type attribute
00352 Paramters:
00353 el -- MessageInterface representing the element
00354 '''
00355 if kw.get('typed', self.typed):
00356 namespaceURI,typeName = kw.get('type', _get_xsitype(self))
00357 if namespaceURI and typeName:
00358 self.logger.debug("attribute: (%s, %s)", namespaceURI, typeName)
00359 el.setAttributeType(namespaceURI, typeName)
00360
00361 def set_attribute_href(self, el, objid):
00362 '''set href attribute
00363 Paramters:
00364 el -- MessageInterface representing the element
00365 objid -- ID type, unique id
00366 '''
00367 el.setAttributeNS(None, 'href', "#%s" %objid)
00368
00369 def set_attribute_id(self, el, objid):
00370 '''set id attribute
00371 Paramters:
00372 el -- MessageInterface representing the element
00373 objid -- ID type, unique id
00374 '''
00375 if self.unique is False:
00376 el.setAttributeNS(None, 'id', "%s" %objid)
00377
00378 def get_name(self, name, objid):
00379 '''
00380 Paramters:
00381 name -- element tag
00382 objid -- ID type, unique id
00383 '''
00384 if type(name) is tuple:
00385 return name
00386
00387 ns = self.nspname
00388 n = name or self.pname or ('E' + objid)
00389 return ns,n
00390
00391 def has_attributes(self):
00392 '''Return True if Attributes are declared outside
00393 the scope of SOAP ('root', 'id', 'href'), and some
00394 attributes automatically handled (xmlns, xsi:type).
00395 '''
00396 if self.attribute_typecode_dict is None: return False
00397 return len(self.attribute_typecode_dict) > 0
00398
00399
00400 class SimpleType(TypeCode):
00401 '''SimpleType -- consist exclusively of a tag, attributes, and a value
00402 class attributes:
00403 empty_content -- value representing an empty element.
00404 '''
00405 empty_content = None
00406 logger = _GetLogger('ZSI.TC.SimpleType')
00407
00408 def parse(self, elt, ps):
00409 self.checkname(elt, ps)
00410 if len(_children(elt)) == 0:
00411 href = _find_href(elt)
00412 if not href:
00413 if self.nilled(elt, ps) is False:
00414
00415 return self.text_to_data(self.empty_content, elt, ps)
00416
00417
00418 if self.nillable is True:
00419 return Nilled
00420 raise EvaluateException('Requiredstring missing',
00421 ps.Backtrace(elt))
00422
00423 if href[0] != '#':
00424 return ps.ResolveHREF(href, self)
00425
00426 elt = ps.FindLocalHREF(href, elt)
00427 self.checktype(elt, ps)
00428 if self.nilled(elt, ps): return Nilled
00429 if len(_children(elt)) == 0:
00430 v = self.empty_content
00431 else:
00432 v = self.simple_value(elt, ps)
00433 else:
00434 v = self.simple_value(elt, ps)
00435
00436 pyobj = self.text_to_data(v, elt, ps)
00437
00438
00439
00440
00441 if self.attribute_typecode_dict is not None:
00442 attributes = self.parse_attributes(elt, ps)
00443 if attributes:
00444 setattr(pyobj, self.attrs_aname, attributes)
00445
00446 return pyobj
00447
00448 def get_formatted_content(self, pyobj):
00449 raise NotImplementedError, 'method get_formatted_content is not implemented'
00450
00451 def serialize_text_node(self, elt, sw, pyobj):
00452 '''Serialize without an element node.
00453 '''
00454 textNode = None
00455 if pyobj is not None:
00456 text = self.get_formatted_content(pyobj)
00457 if type(text) not in _stringtypes:
00458 raise TypeError, 'pyobj must be a formatted string'
00459
00460 textNode = elt.createAppendTextNode(text)
00461
00462 return textNode
00463
00464 def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
00465 '''Handles the start and end tags, and attributes. callout
00466 to get_formatted_content to get the textNode value.
00467 Parameters:
00468 elt -- ElementProxy/DOM element
00469 sw -- SoapWriter instance
00470 pyobj -- processed content
00471
00472 KeyWord Parameters:
00473 name -- substitute name, (nspname,name) or name
00474 orig --
00475
00476 '''
00477 objid = _get_idstr(pyobj)
00478 ns,n = self.get_name(name, objid)
00479
00480
00481 el = elt.createAppendElement(ns, n)
00482 if self.nillable is True and pyobj is Nilled:
00483 self.serialize_as_nil(el)
00484 return None
00485
00486
00487 self.set_attributes(el, pyobj)
00488
00489
00490 unique = self.unique or kw.get('unique', False)
00491 if unique is False and sw.Known(orig or pyobj):
00492 self.set_attribute_href(el, objid)
00493 return None
00494
00495
00496 if kw.get('typed', self.typed) is True:
00497 self.set_attribute_xsi_type(el, **kw)
00498
00499
00500 if self.unique is False:
00501 self.set_attribute_id(el, objid)
00502
00503
00504 self.serialize_text_node(el, sw, pyobj)
00505
00506 return el
00507
00508
00509 class Any(TypeCode):
00510 '''When the type isn't defined in the schema, but must be specified
00511 in the incoming operation.
00512 parsemap -- a type to class mapping (updated by descendants), for
00513 parsing
00514 serialmap -- same, for (outgoing) serialization
00515 '''
00516 logger = _GetLogger('ZSI.TC.Any')
00517 parsemap, serialmap = {}, {}
00518
00519 def __init__(self, pname=None, aslist=False, minOccurs=0, unique=False, **kw):
00520 TypeCode.__init__(self, pname, minOccurs=minOccurs, unique=unique, **kw)
00521 self.aslist = aslist
00522 self.kwargs = dict(aslist=aslist, unique=unique)
00523 self.kwargs.update(kw)
00524
00525
00526 def listify(self, v):
00527 if self.aslist: return [ k for j,k in v ]
00528 return dict(v)
00529
00530 def parse_into_dict_or_list(self, elt, ps):
00531 c = _child_elements(elt)
00532 count = len(c)
00533 v = []
00534 if count == 0:
00535 href = _find_href(elt)
00536 if not href: return v
00537 elt = ps.FindLocalHREF(href, elt)
00538 self.checktype(elt, ps)
00539 c = _child_elements(elt)
00540 count = len(c)
00541 if count == 0: return self.listify(v)
00542 if self.nilled(elt, ps): return Nilled
00543
00544 for c_elt in c:
00545 v.append((str(c_elt.localName), self.__class__(**self.kwargs).parse(c_elt, ps)))
00546
00547 return self.listify(v)
00548
00549 def parse(self, elt, ps):
00550 (ns,type) = self.checkname(elt, ps)
00551 if not type and self.nilled(elt, ps): return Nilled
00552 if len(_children(elt)) == 0:
00553 href = _find_href(elt)
00554 if not href:
00555 if self.minOccurs < 1:
00556 if _is_xsd_or_soap_ns(ns):
00557 parser = Any.parsemap.get((None,type))
00558 if parser: return parser.parse(elt, ps)
00559 if ((ns,type) == (SOAP.ENC,'Array') or
00560 (_find_arraytype(elt) or '').endswith('[0]')):
00561 return []
00562 return None
00563 raise EvaluateException('Required Any missing',
00564 ps.Backtrace(elt))
00565 elt = ps.FindLocalHREF(href, elt)
00566 (ns,type) = self.checktype(elt, ps)
00567 if not type and elt.namespaceURI == SOAP.ENC:
00568 ns,type = SOAP.ENC, elt.localName
00569 if not type or (ns,type) == (SOAP.ENC,'Array'):
00570 if self.aslist or _find_arraytype(elt):
00571 return [ self.__class__(**self.kwargs).parse(e, ps)
00572 for e in _child_elements(elt) ]
00573 if len(_child_elements(elt)) == 0:
00574
00575
00576 return self.simple_value(elt, ps)
00577 return self.parse_into_dict_or_list(elt, ps)
00578 parser = Any.parsemap.get((ns,type))
00579 if not parser and _is_xsd_or_soap_ns(ns):
00580 parser = Any.parsemap.get((None,type))
00581 if not parser:
00582 raise EvaluateException('''Any can't parse element''',
00583 ps.Backtrace(elt))
00584 return parser.parse(elt, ps)
00585
00586 def get_formatted_content(self, pyobj):
00587 tc = type(pyobj)
00588 if tc == types.InstanceType:
00589 tc = pyobj.__class__
00590 if hasattr(pyobj, 'typecode'):
00591
00592 serializer = pyobj.typecode
00593 else:
00594 serializer = Any.serialmap.get(tc)
00595 if not serializer:
00596 tc = (types.ClassType, pyobj.__class__.__name__)
00597 serializer = Any.serialmap.get(tc)
00598 else:
00599 serializer = Any.serialmap.get(tc)
00600 if not serializer and isinstance(pyobj, time.struct_time):
00601 from ZSI.TCtimes import gDateTime
00602 serializer = gDateTime()
00603 if serializer:
00604 return serializer.get_formatted_content(pyobj)
00605 raise EvaluateException, 'Failed to find serializer for pyobj %s' %pyobj
00606
00607 def serialize(self, elt, sw, pyobj, name=None, **kw):
00608 if hasattr(pyobj, 'typecode') and pyobj.typecode is not self:
00609 pyobj.typecode.serialize(elt, sw, pyobj, **kw)
00610 return
00611
00612 objid = _get_idstr(pyobj)
00613 ns,n = self.get_name(name, objid)
00614 kw.setdefault('typed', self.typed)
00615 tc = type(pyobj)
00616 self.logger.debug('Any serialize -- %s', tc)
00617 if tc in _seqtypes:
00618 if self.aslist:
00619 array = elt.createAppendElement(ns, n)
00620 array.setAttributeType(SOAP.ENC, "Array")
00621 array.setAttributeNS(self.nspname, 'SOAP-ENC:arrayType',
00622 "xsd:anyType[" + str(len(pyobj)) + "]" )
00623 for o in pyobj:
00624
00625 serializer = getattr(o, 'typecode', Any(**self.kwargs))
00626 serializer.serialize(array, sw, o, name='element', **kw)
00627 else:
00628 struct = elt.createAppendElement(ns, n)
00629 for o in pyobj:
00630
00631 serializer = getattr(o, 'typecode', Any(**self.kwargs))
00632 serializer.serialize(struct, sw, o, **kw)
00633 return
00634
00635 kw['name'] = (ns,n)
00636 if tc == types.DictType:
00637 el = elt.createAppendElement(ns, n)
00638 parentNspname = self.nspname
00639 self.nspname = None
00640 for o,m in pyobj.items():
00641 if type(o) != types.StringType and type(o) != types.UnicodeType:
00642 raise Exception, 'Dictionary implementation requires keys to be of type string (or unicode).' %pyobj
00643 kw['name'] = o
00644 kw.setdefault('typed', True)
00645 self.serialize(el, sw, m, **kw)
00646
00647 self.nspname = parentNspname
00648 return
00649
00650 if tc == types.InstanceType:
00651 tc = pyobj.__class__
00652 if hasattr(pyobj, 'typecode'):
00653
00654 serializer = pyobj.typecode
00655 else:
00656 serializer = Any.serialmap.get(tc)
00657 if not serializer:
00658 tc = (types.ClassType, pyobj.__class__.__name__)
00659 serializer = Any.serialmap.get(tc)
00660 else:
00661 serializer = Any.serialmap.get(tc)
00662 if not serializer and isinstance(pyobj, time.struct_time):
00663 from ZSI.TCtimes import gDateTime
00664 serializer = gDateTime()
00665
00666 if not serializer:
00667
00668 if pyobj is None:
00669 self.serialize_as_nil(elt.createAppendElement(ns, n))
00670 elif type(pyobj) != types.InstanceType:
00671 raise EvaluateException('''Any can't serialize ''' + \
00672 repr(pyobj))
00673 else:
00674 self.serialize(elt, sw, pyobj.__dict__, **kw)
00675 else:
00676
00677 tag = getattr(serializer, 'tag', None)
00678 if self.pname is not None:
00679
00680
00681 if "typed" not in kw:
00682 kw['typed'] = False
00683 elif tag:
00684 if tag.find(':') == -1: tag = 'SOAP-ENC:' + tag
00685 kw['name'] = tag
00686 kw['typed'] = False
00687
00688 serializer.unique = self.unique
00689 serializer.serialize(elt, sw, pyobj, **kw)
00690
00691
00692
00693
00694
00695 class String(SimpleType):
00696 '''A string type.
00697 '''
00698 empty_content = ''
00699 parselist = [ (None,'string') ]
00700 seriallist = [ types.StringType, types.UnicodeType ]
00701 type = (SCHEMA.XSD3, 'string')
00702 logger = _GetLogger('ZSI.TC.String')
00703
00704 def __init__(self, pname=None, strip=True, **kw):
00705 TypeCode.__init__(self, pname, **kw)
00706 if kw.has_key('resolver'): self.resolver = kw['resolver']
00707 self.strip = strip
00708
00709 def text_to_data(self, text, elt, ps):
00710 '''convert text into typecode specific data.
00711 Encode all strings as UTF-8, which will be type 'str'
00712 not 'unicode'
00713 '''
00714 if self.strip: text = text.strip()
00715 if self.pyclass is not None:
00716 return self.pyclass(text.encode(UNICODE_ENCODING))
00717 return text.encode(UNICODE_ENCODING)
00718
00719 def get_formatted_content(self, pyobj):
00720 if type(pyobj) not in _stringtypes:
00721 pyobj = str(pyobj)
00722 if type(pyobj) == unicode:
00723 return pyobj.encode(UNICODE_ENCODING)
00724 return pyobj
00725
00726
00727 class URI(String):
00728 '''A URI.
00729 Class data:
00730 reserved -- urllib.quote will escape all reserved characters
00731 regardless of whether they are used for the reserved purpose.
00732
00733 '''
00734 parselist = [ (None,'anyURI'),(SCHEMA.XSD3, 'anyURI')]
00735 type = (SCHEMA.XSD3, 'anyURI')
00736 logger = _GetLogger('ZSI.TC.URI')
00737 reserved = ";/?:@&=+$,"
00738
00739 def text_to_data(self, text, elt, ps):
00740 '''text --> typecode specific data.
00741 '''
00742 return String.text_to_data(self, urldecode(text), elt, ps)
00743
00744 def get_formatted_content(self, pyobj):
00745 '''typecode data --> text
00746 '''
00747 u = urlencode(pyobj, self.reserved)
00748 return String.get_formatted_content(self,
00749 u)
00750
00751
00752 class QName(String):
00753 '''A QName type
00754 '''
00755 parselist = [ (None,'QName') ]
00756 type = (SCHEMA.XSD3, 'QName')
00757 logger = _GetLogger('ZSI.TC.QName')
00758
00759 def __init__(self, pname=None, strip=1, **kw):
00760 String.__init__(self, pname, strip, **kw)
00761 self.prefix = None
00762
00763 def get_formatted_content(self, pyobj):
00764 value = pyobj
00765 if isinstance(pyobj, tuple):
00766 namespaceURI,localName = pyobj
00767 if self.prefix is not None:
00768 value = "%s:%s" %(self.prefix,localName)
00769 return String.get_formatted_content(self, value)
00770
00771 def set_prefix(self, elt, pyobj):
00772 '''use this method to set the prefix of the QName,
00773 method looks in DOM to find prefix or set new prefix.
00774 This method must be called before get_formatted_content.
00775 '''
00776 if isinstance(pyobj, tuple):
00777 namespaceURI,localName = pyobj
00778 self.prefix = elt.getPrefix(namespaceURI)
00779
00780 def text_to_data(self, text, elt, ps):
00781 '''convert text into typecode specific data.
00782 '''
00783 prefix,localName = SplitQName(text)
00784 nsdict = ps.GetElementNSdict(elt)
00785 prefix = prefix or ''
00786 try:
00787 namespaceURI = nsdict[prefix]
00788 except KeyError, ex:
00789 raise EvaluateException('cannot resolve prefix(%s)'%prefix,
00790 ps.Backtrace(elt))
00791
00792 v = (namespaceURI,localName)
00793 if self.pyclass is not None:
00794 return self.pyclass(v)
00795 return v
00796
00797 def serialize_text_node(self, elt, sw, pyobj):
00798 '''Serialize without an element node.
00799 '''
00800 self.set_prefix(elt, pyobj)
00801 return String.serialize_text_node(self, elt, sw, pyobj)
00802
00803
00804 class Token(String):
00805 '''an xsd:token type
00806 '''
00807 parselist = [ (None, 'token') ]
00808 type = (SCHEMA.XSD3, 'token')
00809 logger = _GetLogger('ZSI.TC.Token')
00810
00811
00812 class Base64String(String):
00813 '''A Base64 encoded string.
00814 '''
00815 parselist = [ (None,'base64Binary'), (SOAP.ENC, 'base64') ]
00816 type = (SOAP.ENC, 'base64')
00817 logger = _GetLogger('ZSI.TC.Base64String')
00818
00819 def text_to_data(self, text, elt, ps):
00820 '''convert text into typecode specific data.
00821 '''
00822 val = b64decode(text.replace(' ', '').replace('\n','').replace('\r',''))
00823 if self.pyclass is not None:
00824 return self.pyclass(val)
00825 return val
00826
00827 def get_formatted_content(self, pyobj):
00828 pyobj = '\n' + b64encode(pyobj)
00829 return String.get_formatted_content(self, pyobj)
00830
00831
00832 class Base64Binary(String):
00833 parselist = [ (None,'base64Binary'), ]
00834 type = (SCHEMA.XSD3, 'base64Binary')
00835 logger = _GetLogger('ZSI.TC.Base64Binary')
00836
00837 def text_to_data(self, text, elt, ps):
00838 '''convert text into typecode specific data.
00839 '''
00840 val = b64decode(text)
00841 if self.pyclass is not None:
00842 return self.pyclass(val)
00843 return val
00844
00845 def get_formatted_content(self, pyobj):
00846 pyobj = b64encode(pyobj).strip()
00847 return pyobj
00848
00849
00850 class HexBinaryString(String):
00851 '''Hex-encoded binary (yuk).
00852 '''
00853 parselist = [ (None,'hexBinary') ]
00854 type = (SCHEMA.XSD3, 'hexBinary')
00855 logger = _GetLogger('ZSI.TC.HexBinaryString')
00856
00857 def text_to_data(self, text, elt, ps):
00858 '''convert text into typecode specific data.
00859 '''
00860 val = hexdecode(text)
00861 if self.pyclass is not None:
00862 return self.pyclass(val)
00863 return val
00864
00865 def get_formatted_content(self, pyobj):
00866 pyobj = hexencode(pyobj).upper()
00867 return String.get_formatted_content(self, pyobj)
00868
00869
00870 class XMLString(String):
00871 '''A string that represents an XML document
00872 '''
00873 logger = _GetLogger('ZSI.TC.XMLString')
00874
00875 def __init__(self, pname=None, readerclass=None, **kw):
00876 String.__init__(self, pname, **kw)
00877 self.readerclass = readerclass
00878
00879 def parse(self, elt, ps):
00880 if not self.readerclass:
00881 from xml.dom.ext.reader import PyExpat
00882 self.readerclass = PyExpat.Reader
00883 v = String.parse(self, elt, ps)
00884 return self.readerclass().fromString(v)
00885
00886 def get_formatted_content(self, pyobj):
00887
00888 return String.get_formatted_content(self, pyobj)
00889
00890
00891 class Enumeration(String):
00892 '''A string type, limited to a set of choices.
00893 '''
00894 logger = _GetLogger('ZSI.TC.Enumeration')
00895
00896 def __init__(self, choices, pname=None, **kw):
00897 String.__init__(self, pname, **kw)
00898 t = type(choices)
00899 if t in _seqtypes:
00900 self.choices = tuple(choices)
00901 elif TypeCode.typechecks:
00902 raise TypeError(
00903 'Enumeration choices must be list or sequence, not ' + str(t))
00904 if TypeCode.typechecks:
00905 for c in self.choices:
00906 if type(c) not in _stringtypes:
00907 raise TypeError(
00908 'Enumeration choice ' + str(c) + ' is not a string')
00909
00910 def parse(self, elt, ps):
00911 val = String.parse(self, elt, ps)
00912 if val not in self.choices:
00913 raise EvaluateException('Value not in enumeration list',
00914 ps.Backtrace(elt))
00915 return val
00916
00917 def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
00918 if pyobj not in self.choices:
00919 raise EvaluateException('Value not in enumeration list',
00920 sw.Backtrace(elt))
00921 String.serialize(self, elt, sw, pyobj, name=name, orig=orig, **kw)
00922
00923
00924
00925
00926 _ignored = []
00927
00928 class Integer(SimpleType):
00929 '''Common handling for all integers.
00930 '''
00931
00932 ranges = {
00933 'unsignedByte': (0, 255),
00934 'unsignedShort': (0, 65535),
00935 'unsignedInt': (0, 4294967295L),
00936 'unsignedLong': (0, 18446744073709551615L),
00937
00938 'byte': (-128, 127),
00939 'short': (-32768, 32767),
00940 'int': (-2147483648L, 2147483647),
00941 'long': (-9223372036854775808L, 9223372036854775807L),
00942
00943 'negativeInteger': (_ignored, -1),
00944 'nonPositiveInteger': (_ignored, 0),
00945 'nonNegativeInteger': (0, _ignored),
00946 'positiveInteger': (1, _ignored),
00947
00948 'integer': (_ignored, _ignored)
00949 }
00950 parselist = [ (None,k) for k in ranges.keys() ]
00951 seriallist = [ types.IntType, types.LongType ]
00952 logger = _GetLogger('ZSI.TC.Integer')
00953
00954 def __init__(self, pname=None, format='%d', **kw):
00955 TypeCode.__init__(self, pname, **kw)
00956 self.format = format
00957
00958 def text_to_data(self, text, elt, ps):
00959 '''convert text into typecode specific data.
00960 '''
00961 if self.pyclass is not None:
00962 v = self.pyclass(text)
00963 else:
00964 try:
00965 v = int(text)
00966 except:
00967 try:
00968 v = long(text)
00969 except:
00970 raise EvaluateException('Unparseable integer',
00971 ps.Backtrace(elt))
00972 return v
00973
00974 def parse(self, elt, ps):
00975 (ns,type) = self.checkname(elt, ps)
00976 if self.nilled(elt, ps): return Nilled
00977 elt = self.SimpleHREF(elt, ps, 'integer')
00978 if not elt: return None
00979
00980 if type is None:
00981 type = self.type[1]
00982 elif self.type[1] is not None and type != self.type[1]:
00983 raise EvaluateException('Integer type mismatch; ' \
00984 'got %s wanted %s' % (type,self.type[1]), ps.Backtrace(elt))
00985
00986 v = self.simple_value(elt, ps)
00987 v = self.text_to_data(v, elt, ps)
00988
00989 (rmin, rmax) = Integer.ranges.get(type, (_ignored, _ignored))
00990 if rmin != _ignored and v < rmin:
00991 raise EvaluateException('Underflow, less than ' + repr(rmin),
00992 ps.Backtrace(elt))
00993 if rmax != _ignored and v > rmax:
00994 raise EvaluateException('Overflow, greater than ' + repr(rmax),
00995 ps.Backtrace(elt))
00996 return v
00997
00998 def get_formatted_content(self, pyobj):
00999 return self.format %pyobj
01000
01001
01002
01003
01004 def _make_inf():
01005 x = 2.0
01006 x2 = x * x
01007 i = 0
01008 while i < 100 and x != x2:
01009 x = x2
01010 x2 = x * x
01011 i = i + 1
01012 if x != x2:
01013 raise ValueError("This machine's floats go on forever!")
01014 return x
01015
01016
01017 _magicnums = { }
01018 try:
01019 _magicnums['INF'] = float('INF')
01020 _magicnums['-INF'] = float('-INF')
01021 except:
01022 _magicnums['INF'] = _make_inf()
01023 _magicnums['-INF'] = -_magicnums['INF']
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 def isnan(x):
01056 """x -> true iff x is a NaN."""
01057
01058
01059 if x * 1.0 < x:
01060
01061 return 1
01062
01063
01064
01065
01066 return 1.0 == x and x == 2.0
01067
01068
01069 class Decimal(SimpleType):
01070 '''Parent class for floating-point numbers.
01071 '''
01072
01073 parselist = [ (None,'decimal'), (None,'float'), (None,'double') ]
01074 seriallist = _floattypes
01075 type = None
01076 ranges = {
01077 'float': ( 7.0064923216240861E-46,
01078 -3.4028234663852886E+38, 3.4028234663852886E+38 ),
01079 'double': ( 2.4703282292062327E-324,
01080 -1.7976931348623158E+308, 1.7976931348623157E+308),
01081 }
01082 zeropat = re.compile('[1-9]')
01083 logger = _GetLogger('ZSI.TC.Decimal')
01084
01085 def __init__(self, pname=None, format='%f', **kw):
01086 TypeCode.__init__(self, pname, **kw)
01087 self.format = format
01088
01089
01090 def text_to_data(self, text, elt, ps):
01091 '''convert text into typecode specific data.
01092 '''
01093 v = text
01094 if self.pyclass is not None:
01095 return self.pyclass(v)
01096
01097 m = _magicnums.get(v)
01098 if m: return m
01099
01100 try:
01101 return float(v)
01102 except:
01103 raise EvaluateException('Unparseable floating point number',
01104 ps.Backtrace(elt))
01105
01106 def parse(self, elt, ps):
01107 (ns,type) = self.checkname(elt, ps)
01108 elt = self.SimpleHREF(elt, ps, 'floating-point')
01109 if not elt: return None
01110 tag = getattr(self.__class__, 'type')
01111 if tag:
01112 if type is None:
01113 type = tag
01114 elif tag != (ns,type):
01115 raise EvaluateException('Floating point type mismatch; ' \
01116 'got (%s,%s) wanted %s' % (ns,type,tag), ps.Backtrace(elt))
01117
01118 if self.nilled(elt, ps): return Nilled
01119 v = self.simple_value(elt, ps)
01120 try:
01121 fp = self.text_to_data(v, elt, ps)
01122 except EvaluateException, ex:
01123 ex.args.append(ps.Backtrace(elt))
01124 raise ex
01125
01126 m = _magicnums.get(v)
01127 if m:
01128 return m
01129
01130 if str(fp).lower() in [ 'inf', '-inf', 'nan', '-nan' ]:
01131 raise EvaluateException('Floating point number parsed as "' + \
01132 str(fp) + '"', ps.Backtrace(elt))
01133 if fp == 0 and Decimal.zeropat.search(v):
01134 raise EvaluateException('Floating point number parsed as zero',
01135 ps.Backtrace(elt))
01136 (rtiny, rneg, rpos) = Decimal.ranges.get(type, (None, None, None))
01137 if rneg and fp < 0 and fp < rneg:
01138 raise EvaluateException('Negative underflow', ps.Backtrace(elt))
01139 if rtiny and fp > 0 and fp < rtiny:
01140 raise EvaluateException('Positive underflow', ps.Backtrace(elt))
01141 if rpos and fp > 0 and fp > rpos:
01142 raise EvaluateException('Overflow', ps.Backtrace(elt))
01143 return fp
01144
01145 def get_formatted_content(self, pyobj):
01146 if pyobj == _magicnums['INF']:
01147 return 'INF'
01148 elif pyobj == _magicnums['-INF']:
01149 return '-INF'
01150 elif isnan(pyobj):
01151 return 'NaN'
01152 else:
01153 return self.format %pyobj
01154
01155
01156 class Boolean(SimpleType):
01157 '''A boolean.
01158 '''
01159
01160 parselist = [ (None,'boolean') ]
01161 seriallist = [ bool ]
01162 type = (SCHEMA.XSD3, 'boolean')
01163 logger = _GetLogger('ZSI.TC.Boolean')
01164
01165 def text_to_data(self, text, elt, ps):
01166 '''convert text into typecode specific data.
01167 '''
01168 v = text
01169 if v == 'false':
01170 if self.pyclass is None:
01171 return False
01172 return self.pyclass(False)
01173
01174 if v == 'true':
01175 if self.pyclass is None:
01176 return True
01177 return self.pyclass(True)
01178
01179 try:
01180 v = int(v)
01181 except:
01182 try:
01183 v = long(v)
01184 except:
01185 raise EvaluateException('Unparseable boolean',
01186 ps.Backtrace(elt))
01187
01188 if v:
01189 if self.pyclass is None:
01190 return True
01191 return self.pyclass(True)
01192
01193 if self.pyclass is None:
01194 return False
01195 return self.pyclass(False)
01196
01197 def parse(self, elt, ps):
01198 self.checkname(elt, ps)
01199 elt = self.SimpleHREF(elt, ps, 'boolean')
01200 if not elt: return None
01201 if self.nilled(elt, ps): return Nilled
01202
01203 v = self.simple_value(elt, ps).lower()
01204 return self.text_to_data(v, elt, ps)
01205
01206 def get_formatted_content(self, pyobj):
01207 if pyobj: return 'true'
01208 return 'false'
01209
01210
01211
01212 class XML(TypeCode):
01213 '''Opaque XML which shouldn't be parsed.
01214 comments -- preserve comments
01215 inline -- don't href/id when serializing
01216 resolver -- object to resolve href's
01217 wrapped -- put a wrapper element around it
01218 '''
01219
01220
01221 copyit = 0
01222 logger = _GetLogger('ZSI.TC.XML')
01223
01224 def __init__(self, pname=None, comments=0, inline=0, wrapped=True, **kw):
01225 TypeCode.__init__(self, pname, **kw)
01226 self.comments = comments
01227 self.inline = inline
01228 if kw.has_key('resolver'): self.resolver = kw['resolver']
01229 self.wrapped = wrapped
01230 self.copyit = kw.get('copyit', XML.copyit)
01231
01232 def parse(self, elt, ps):
01233 if self.wrapped is False:
01234 return elt
01235 c = _child_elements(elt)
01236 if not c:
01237 href = _find_href(elt)
01238 if not href:
01239 if self.minOccurs == 0: return None
01240 raise EvaluateException('Embedded XML document missing',
01241 ps.Backtrace(elt))
01242 if href[0] != '#':
01243 return ps.ResolveHREF(href, self)
01244 elt = ps.FindLocalHREF(href, elt)
01245 c = _child_elements(elt)
01246 if _find_encstyle(elt) != "":
01247
01248
01249 pass
01250 if len(c) != 1:
01251 raise EvaluateException('Embedded XML has more than one child',
01252 ps.Backtrace(elt))
01253 if self.copyit: return c[0].cloneNode(1)
01254 return c[0]
01255
01256 def serialize(self, elt, sw, pyobj, name=None, unsuppressedPrefixes=[], **kw):
01257 objid = _get_idstr(pyobj)
01258 ns,n = self.get_name(name, objid)
01259
01260 xmlelt = elt
01261 if self.wrapped:
01262 xmlelt = elt.createAppendElement(ns, n)
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274 self.cb(xmlelt, sw, pyobj, unsuppressedPrefixes)
01275
01276 def cb(self, elt, sw, pyobj, unsuppressedPrefixes=[]):
01277 """pyobj -- xml.dom.Node.ELEMENT_NODE
01278 """
01279
01280
01281
01282 if type(pyobj) in _stringtypes:
01283 elt.createAppendTextNode(pyobj)
01284 return
01285
01286
01287 doc = elt.getDocument()
01288 node = doc.importNode(pyobj, deep=1)
01289 child = elt.node.appendChild(node)
01290
01291
01292 parent = pyobj.parentNode
01293 while parent.nodeType == _Node.ELEMENT_NODE:
01294 for attr in filter(lambda a: a.name.startswith('xmlns:') and a.name not in child.attributes.keys(), parent.attributes):
01295 child.setAttributeNode(attr.cloneNode(1))
01296
01297 parent = parent.parentNode
01298
01299
01300 class AnyType(TypeCode):
01301 """XML Schema xsi:anyType type definition wildCard.
01302 class variables:
01303 all -- specifies use of all namespaces.
01304 other -- specifies use of other namespaces
01305 type --
01306 """
01307 all = '#all'
01308 other = '#other'
01309 type = (SCHEMA.XSD3, 'anyType')
01310 logger = _GetLogger('ZSI.TC.AnyType')
01311
01312 def __init__(self, pname=None, namespaces=['#all'],
01313 minOccurs=1, maxOccurs=1, strip=1, **kw):
01314 TypeCode.__init__(self, pname=pname, minOccurs=minOccurs,
01315 maxOccurs=maxOccurs, **kw)
01316 self.namespaces = namespaces
01317
01318 def get_formatted_content(self, pyobj):
01319
01320
01321 what = getattr(pyobj, 'typecode', Any())
01322 return what.get_formatted_content(pyobj)
01323
01324 def text_to_data(self, text, elt, ps):
01325 '''convert text into typecode specific data. Used only with
01326 attributes so will not know anything about this content so
01327 why guess?
01328 Parameters:
01329 text -- text content
01330 elt -- the DOM element being parsed
01331 ps -- the ParsedSoap object.
01332 '''
01333 return text
01334
01335 def serialize(self, elt, sw, pyobj, **kw):
01336 nsuri,typeName = _get_xsitype(pyobj)
01337 if self.all not in self.namespaces and nsuri not in self.namespaces:
01338 raise EvaluateException(
01339 '<anyType> unsupported use of namespaces "%s"' %self.namespaces)
01340
01341 what = getattr(pyobj, 'typecode', None)
01342 if what is None:
01343
01344
01345
01346 what = Any(pname=(self.nspname,self.pname), unique=True,
01347 aslist=False)
01348 kw['typed'] = True
01349 what.serialize(elt, sw, pyobj, **kw)
01350 return
01351
01352
01353 what.serialize(elt, sw, pyobj,
01354 name=(self.nspname or what.nspname, self.pname or what.pname), **kw)
01355
01356 def parse(self, elt, ps):
01357
01358 nspname,pname = _get_element_nsuri_name(elt)
01359 if nspname != self.nspname or pname != self.pname:
01360 raise EvaluateException('<anyType> instance is (%s,%s) found (%s,%s)' %(
01361 self.nspname,self.pname,nspname,pname), ps.Backtrace(elt))
01362
01363
01364 prefix, typeName = SplitQName(_find_type(elt))
01365 namespaceURI = _resolve_prefix(elt, prefix)
01366 pyclass = GTD(namespaceURI, typeName)
01367 if not pyclass:
01368 if _is_xsd_or_soap_ns(namespaceURI):
01369 pyclass = Any
01370 elif (str(namespaceURI).lower()==str(Apache.Map.type[0]).lower())\
01371 and (str(typeName).lower() ==str(Apache.Map.type[1]).lower()):
01372 pyclass = Apache.Map
01373 else:
01374
01375 pyobj = Any().parse_into_dict_or_list(elt, ps)
01376 return pyobj
01377
01378 what = pyclass(pname=(self.nspname,self.pname))
01379 pyobj = what.parse(elt, ps)
01380 return pyobj
01381
01382
01383 class AnyElement(AnyType):
01384 """XML Schema xsi:any element declaration wildCard.
01385 class variables:
01386 tag -- global element declaration
01387 """
01388 tag = (SCHEMA.XSD3, 'any')
01389 logger = _GetLogger('ZSI.TC.AnyElement')
01390
01391 def __init__(self, namespaces=['#all'],pname=None,
01392 minOccurs=1, maxOccurs=1, strip=1, processContents='strict',
01393 **kw):
01394
01395 if processContents not in ('lax', 'skip', 'strict'):
01396 raise ValueError('processContents(%s) must be lax, skip, or strict')
01397
01398 self.processContents = processContents
01399 AnyType.__init__(self, namespaces=namespaces,pname=pname,
01400 minOccurs=minOccurs, maxOccurs=maxOccurs, strip=strip, **kw)
01401
01402 def serialize(self, elt, sw, pyobj, **kw):
01403 '''Must provice typecode to AnyElement for serialization, else
01404 try to use TC.Any to serialize instance which will serialize
01405 based on the data type of pyobj w/o reference to XML schema
01406 instance.
01407 '''
01408 if isinstance(pyobj, TypeCode):
01409 raise TypeError, 'pyobj is a typecode instance.'
01410
01411 what = getattr(pyobj, 'typecode', None)
01412 if what is not None and type(pyobj) is types.InstanceType:
01413 tc = pyobj.__class__
01414 what = Any.serialmap.get(tc)
01415 if not what:
01416 tc = (types.ClassType, pyobj.__class__.__name__)
01417 what = Any.serialmap.get(tc)
01418
01419 self.logger.debug('processContents: %s', self.processContents)
01420
01421
01422 if what is None:
01423
01424
01425 what = Any(pname=(self.nspname,self.pname))
01426
01427 self.logger.debug('serialize with %s', what.__class__.__name__)
01428 what.serialize(elt, sw, pyobj, **kw)
01429
01430 def parse(self, elt, ps):
01431 '''
01432 processContents -- 'lax' | 'skip' | 'strict', 'strict'
01433 1) if 'skip' check namespaces, and return the DOM node.
01434 2) if 'lax' look for declaration, or definition. If
01435 not found return DOM node.
01436 3) if 'strict' get declaration, or raise.
01437 '''
01438 skip = self.processContents == 'skip'
01439 nspname,pname = _get_element_nsuri_name(elt)
01440 what = GED(nspname, pname)
01441 if not skip and what is not None:
01442 pyobj = what.parse(elt, ps)
01443 try:
01444 pyobj.typecode = what
01445 except AttributeError, ex:
01446
01447 pyobj = WrapImmutable(pyobj, what)
01448 return pyobj
01449
01450
01451
01452 prefix, typeName = SplitQName(_find_type(elt))
01453 if not skip and typeName:
01454 namespaceURI = _resolve_prefix(elt, prefix or 'xmlns')
01455
01456
01457 pyclass = GTD(namespaceURI, typeName) or Any
01458 what = pyclass(pname=(nspname,pname))
01459 pyobj = what.parse(elt, ps)
01460 try:
01461 pyobj.typecode = what
01462 except AttributeError, ex:
01463
01464 pyobj = WrapImmutable(pyobj, what)
01465
01466 what.typed = True
01467 return pyobj
01468
01469 if skip:
01470 what = XML(pname=(nspname,pname), wrapped=False)
01471 elif self.processContents == 'lax':
01472 what = Any(pname=(nspname,pname), unique=True)
01473 else:
01474 what = Any(pname=(nspname,pname), unique=True)
01475
01476 try:
01477 pyobj = what.parse(elt, ps)
01478 except EvaluateException, ex:
01479 self.logger.debug("error parsing: %s" %str(ex))
01480
01481 if len(_children(elt)) != 0:
01482 self.logger.debug('parse <any>, return as dict')
01483 return Any(aslist=False).parse_into_dict_or_list(elt, ps)
01484
01485 self.logger.debug("Give up, parse (%s,%s) as a String",
01486 what.nspname, what.pname)
01487 what = String(pname=(nspname,pname), typed=False)
01488 return WrapImmutable(what.parse(elt, ps), what)
01489
01490 if pyobj is None:
01491 return
01492
01493
01494 if type(pyobj) is dict:
01495 return pyobj
01496
01497 try:
01498 pyobj.typecode = what
01499 except AttributeError:
01500 pyobj = WrapImmutable(pyobj, what)
01501
01502 return pyobj
01503
01504
01505
01506 class Union(SimpleType):
01507 '''simpleType Union
01508
01509 class variables:
01510 memberTypes -- list [(namespace,name),] tuples, each representing a type defintion.
01511 '''
01512 memberTypes = None
01513 logger = _GetLogger('ZSI.TC.Union')
01514
01515 def __init__(self, pname=None, minOccurs=1, maxOccurs=1, **kw):
01516 SimpleType.__init__(self, pname=pname, minOccurs=minOccurs, maxOccurs=maxOccurs, **kw)
01517 self.memberTypeCodes = []
01518
01519 def setMemberTypeCodes(self):
01520 if len(self.memberTypeCodes) > 0:
01521 return
01522 if self.__class__.memberTypes is None:
01523 raise EvaluateException, 'uninitialized class variable memberTypes [(namespace,name),]'
01524 for nsuri,name in self.__class__.memberTypes:
01525 tcclass = GTD(nsuri,name)
01526 if tcclass is None:
01527 tc = Any.parsemap.get((nsuri,name)) or Any.parsemap.get((None, name))
01528 typecode = tc.__class__(pname=(self.nspname,self.pname))
01529 else:
01530 typecode = tcclass(pname=(self.nspname,self.pname))
01531
01532 if typecode is None:
01533 raise EvaluateException, \
01534 'Typecode class for Union memberType (%s,%s) is missing' %(nsuri,name)
01535 if isinstance(typecode, Struct):
01536 raise EvaluateException, \
01537 'Illegal: Union memberType (%s,%s) is complexType' %(nsuri,name)
01538 self.memberTypeCodes.append(typecode)
01539
01540 def parse(self, elt, ps, **kw):
01541 '''attempt to parse sequentially. No way to know ahead of time
01542 what this instance represents. Must be simple type so it can
01543 not have attributes nor children, so this isn't too bad.
01544 '''
01545 self.setMemberTypeCodes()
01546 (nsuri,typeName) = self.checkname(elt, ps)
01547
01548
01549
01550
01551
01552
01553 for indx in range(len(self.memberTypeCodes)):
01554 typecode = self.memberTypeCodes[indx]
01555 try:
01556 pyobj = typecode.parse(elt, ps)
01557 except ParseException, ex:
01558 continue
01559 except Exception, ex:
01560 continue
01561
01562 if indx > 0:
01563 self.memberTypeCodes.remove(typecode)
01564 self.memberTypeCodes.insert(0, typecode)
01565 break
01566
01567 else:
01568 raise
01569
01570 return pyobj
01571
01572 def get_formatted_content(self, pyobj, **kw):
01573 self.setMemberTypeCodes()
01574 for indx in range(len(self.memberTypeCodes)):
01575 typecode = self.memberTypeCodes[indx]
01576 try:
01577 content = typecode.get_formatted_content(copy.copy(pyobj))
01578 break
01579 except (ParseException, TypeError):
01580 pass
01581
01582 if indx > 0:
01583 self.memberTypeCodes.remove(typecode)
01584 self.memberTypeCodes.insert(0, typecode)
01585
01586 else:
01587 raise
01588
01589 return content
01590
01591
01592 class List(SimpleType):
01593 '''simpleType List
01594 Class data:
01595 itemType -- sequence (namespaceURI,name) or a TypeCode instance
01596 representing the type definition
01597 '''
01598 itemType = None
01599 logger = _GetLogger('ZSI.TC.List')
01600
01601 def __init__(self, pname=None, itemType=None, **kw):
01602 '''Currently need to require maxOccurs=1, so list
01603 is interpreted as a single unit of data.
01604 '''
01605 assert kw.get('maxOccurs',1) == 1, \
01606 'Currently only supporting SimpleType Lists with maxOccurs=1'
01607
01608 SimpleType.__init__(self, pname=pname, **kw)
01609 self.itemType = itemType or self.itemType
01610 self.itemTypeCode = self.itemType
01611
01612 itemTypeCode = None
01613 if type(self.itemTypeCode) in _seqtypes:
01614 namespaceURI,name = self.itemTypeCode
01615 try:
01616 itemTypeCode = GTD(*self.itemType)(None)
01617 except:
01618 if _is_xsd_or_soap_ns(namespaceURI) is False:
01619 raise
01620 for pyclass in TYPES:
01621 if pyclass.type == self.itemTypeCode:
01622 itemTypeCode = pyclass(None)
01623 break
01624 elif pyclass.type[1] == name:
01625 itemTypeCode = pyclass(None)
01626
01627 if itemTypeCode is None:
01628 raise EvaluateException('Failed to locate %s' %str(self.itemTypeCode))
01629
01630 if hasattr(itemTypeCode, 'text_to_data') is False:
01631 raise EvaluateException('TypeCode class %s missing text_to_data method' %itemTypeCode)
01632
01633 self.itemTypeCode = itemTypeCode
01634
01635
01636 def text_to_data(self, text, elt, ps):
01637 '''convert text into typecode specific data. items in
01638 list are space separated.
01639 '''
01640 v = []
01641 items = text.split()
01642 for item in items:
01643 v.append(self.itemTypeCode.text_to_data(item, elt, ps))
01644
01645 if self.pyclass is not None:
01646 return self.pyclass(v)
01647 return v
01648
01649 def parse(self, elt, ps):
01650 '''elt -- the DOM element being parsed
01651 ps -- the ParsedSoap object.
01652 '''
01653 self.checkname(elt, ps)
01654 if len(_children(elt)) == 0:
01655 href = _find_href(elt)
01656 if not href:
01657 if self.nilled(elt, ps) is False:
01658 return []
01659 if self.nillable is True:
01660 return Nilled
01661 raise EvaluateException('Required string missing',
01662 ps.Backtrace(elt))
01663 if href[0] != '#':
01664 return ps.ResolveHREF(href, self)
01665 elt = ps.FindLocalHREF(href, elt)
01666 self.checktype(elt, ps)
01667
01668 if self.nilled(elt, ps): return Nilled
01669 if len(_children(elt)) == 0: return []
01670
01671 v = self.simple_value(elt, ps)
01672 return self.text_to_data(v, elt, ps)
01673
01674
01675 def serialize(self, elt, sw, pyobj, name=None, orig=None, **kw):
01676 '''elt -- the current DOMWrapper element
01677 sw -- soapWriter object
01678 pyobj -- python object to serialize
01679 '''
01680 if pyobj is not None and type(pyobj) not in _seqtypes:
01681 raise EvaluateException, 'expecting a list or None'
01682
01683 objid = _get_idstr(pyobj)
01684 ns,n = self.get_name(name, objid)
01685 el = elt.createAppendElement(ns, n)
01686 if self.nillable is True and pyobj is None:
01687 self.serialize_as_nil(el)
01688 return None
01689
01690 tc = self.itemTypeCode
01691 s = StringIO(); sep = ' '
01692 for item in pyobj:
01693 s.write(tc.get_formatted_content(item))
01694 s.write(sep)
01695
01696 el.createAppendTextNode(s.getvalue())
01697
01698
01699 def RegisterType(C, clobber=0, *args, **keywords):
01700 instance = apply(C, args, keywords)
01701 for t in C.__dict__.get('parselist', []):
01702 prev = Any.parsemap.get(t)
01703 if prev:
01704 if prev.__class__ == C: continue
01705 if not clobber:
01706 raise TypeError(
01707 str(C) + ' duplicating parse registration for ' + str(t))
01708 Any.parsemap[t] = instance
01709 for t in C.__dict__.get('seriallist', []):
01710 ti = type(t)
01711 if ti in [ types.TypeType, types.ClassType]:
01712 key = t
01713 elif ti in _stringtypes:
01714 key = (types.ClassType, t)
01715 else:
01716 raise TypeError(str(t) + ' is not a class name')
01717 prev = Any.serialmap.get(key)
01718 if prev:
01719 if prev.__class__ == C: continue
01720 if not clobber:
01721 raise TypeError(
01722 str(C) + ' duplicating serial registration for ' + str(t))
01723 Any.serialmap[key] = instance
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787 from TCnumbers import *
01788 from TCtimes import *
01789 from schema import GTD, GED, WrapImmutable
01790 from TCcompound import *
01791 from TCapache import *
01792
01793
01794 _get_type_definition, _get_global_element_declaration, Wrap = GTD, GED, WrapImmutable
01795
01796 f = lambda x: type(x) == types.ClassType and issubclass(x, TypeCode) and getattr(x, 'type', None) is not None
01797 TYPES = filter(f, map(lambda y:eval(y),dir()))
01798
01799
01800 if __name__ == '__main__': print _copyright
01801