Package suds :: Package mx :: Module literal
[hide private]
[frames] | no frames]

Source Code for Module suds.mx.literal

  1  # This program is free software; you can redistribute it and/or modify 
  2  # it under the terms of the (LGPL) GNU Lesser General Public License as 
  3  # published by the Free Software Foundation; either version 3 of the  
  4  # License, or (at your option) any later version. 
  5  # 
  6  # This program is distributed in the hope that it will be useful, 
  7  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  8  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  9  # GNU Library Lesser General Public License for more details at 
 10  # ( http://www.gnu.org/licenses/lgpl.html ). 
 11  # 
 12  # You should have received a copy of the GNU Lesser General Public License 
 13  # along with this program; if not, write to the Free Software 
 14  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 15  # written by: Jeff Ortel ( jortel@redhat.com ) 
 16   
 17  """ 
 18  Provides literal I{marshaller} classes. 
 19  """ 
 20   
 21  from logging import getLogger 
 22  from suds import * 
 23  from suds.mx import * 
 24  from suds.mx.core import Core 
 25  from suds.mx.typer import Typer 
 26  from suds.resolver import GraphResolver, Frame 
 27  from suds.sax.element import Element 
 28  from suds.sudsobject import Factory 
 29   
 30  log = getLogger(__name__) 
 31   
 32   
 33  # 
 34  # Add typed extensions 
 35  # type = The expected xsd type 
 36  # real = The 'true' XSD type 
 37  # ancestry = The 'type' ancestry 
 38  # 
 39  Content.extensions.append('type') 
 40  Content.extensions.append('real') 
 41  Content.extensions.append('ancestry') 
 42   
 43   
 44   
45 -class Typed(Core):
46 """ 47 A I{typed} marshaller. 48 This marshaller is semi-typed as needed to support both 49 I{document/literal} and I{rpc/literal} soap message styles. 50 @ivar schema: An xsd schema. 51 @type schema: L{xsd.schema.Schema} 52 @ivar resolver: A schema type resolver. 53 @type resolver: L{GraphResolver} 54 """ 55
56 - def __init__(self, schema, xstq=True):
57 """ 58 @param schema: A schema object 59 @type schema: L{xsd.schema.Schema} 60 @param xstq: The B{x}ml B{s}chema B{t}ype B{q}ualified flag indicates 61 that the I{xsi:type} attribute values should be qualified by namespace. 62 @type xstq: bool 63 """ 64 Core.__init__(self) 65 self.schema = schema 66 self.xstq = xstq 67 self.resolver = GraphResolver(self.schema)
68
69 - def reset(self):
70 self.resolver.reset()
71
72 - def start(self, content):
73 # 74 # Start marshalling the 'content' by ensuring that both the 75 # 'content' _and_ the resolver are primed with the XSD type 76 # information. The 'content' value is both translated and 77 # sorted based on the XSD type. Only values that are objects 78 # have their attributes sorted. 79 # 80 log.debug('starting content:\n%s', content) 81 if content.type is None: 82 name = content.tag 83 if name.startswith('_'): 84 name = '@'+name[1:] 85 content.type = self.resolver.find(name, content.value) 86 if content.type is None: 87 raise TypeNotFound(content.tag) 88 else: 89 known = None 90 if isinstance(content.value, Object): 91 known = self.resolver.known(content.value) 92 if known is None: 93 log.debug('object has no type information', content.value) 94 known = content.type 95 frame = Frame(content.type, resolved=known) 96 self.resolver.push(frame) 97 frame = self.resolver.top() 98 content.real = frame.resolved 99 content.ancestry = frame.ancestry 100 self.translate(content) 101 self.sort(content) 102 if self.skip(content): 103 log.debug('skipping (optional) content:\n%s', content) 104 self.resolver.pop() 105 return False 106 else: 107 return True
108
109 - def suspend(self, content):
110 # 111 # Suspend to process a list content. Primarily, this 112 # involves popping the 'list' content off the resolver's 113 # stack so the list items can be marshalled. 114 # 115 self.resolver.pop()
116
117 - def resume(self, content):
118 # 119 # Resume processing a list content. To do this, we 120 # really need to simply push the 'list' content 121 # back onto the resolver stack. 122 # 123 self.resolver.push(Frame(content.type))
124
125 - def end(self, parent, content):
126 # 127 # End processing the content. Make sure the content 128 # ending matches the top of the resolver stack since for 129 # list processing we play games with the resolver stack. 130 # 131 log.debug('ending content:\n%s', content) 132 current = self.resolver.top().type 133 if current == content.type: 134 self.resolver.pop() 135 else: 136 raise Exception, \ 137 'content (end) mismatch: top=(%s) cont=(%s)' % \ 138 (current, content)
139
140 - def node(self, content):
141 # 142 # Create an XML node and namespace qualify as defined 143 # by the schema (elementFormDefault). 144 # 145 ns = content.type.namespace() 146 if content.type.form_qualified: 147 node = Element(content.tag, ns=ns) 148 node.addPrefix(ns[0], ns[1]) 149 else: 150 node = Element(content.tag) 151 self.encode(node, content) 152 log.debug('created - node:\n%s', node) 153 return node
154
155 - def setnil(self, node, content):
156 # 157 # Set the 'node' nil only if the XSD type 158 # specifies that it is permitted. 159 # 160 if content.type.nillable: 161 node.setnil()
162
163 - def setdefault(self, node, content):
164 # 165 # Set the node to the default value specified 166 # by the XSD type. 167 # 168 default = content.type.default 169 if default is None: 170 pass 171 else: 172 node.setText(default) 173 return default
174
175 - def optional(self, content):
176 if content.type.optional(): 177 return True 178 for a in content.ancestry: 179 if a.optional(): 180 return True 181 return False
182
183 - def encode(self, node, content):
184 # Add (soap) encoding information only if the resolved 185 # type is derived by extension. Further, the xsi:type values 186 # is qualified by namespace only if the content (tag) and 187 # referenced type are in different namespaces. 188 if content.type.any(): 189 return 190 if not content.real.extension(): 191 return 192 if content.type.resolve() == content.real: 193 return 194 ns = None 195 name = content.real.name 196 if self.xstq: 197 ns = content.real.namespace('ns1') 198 Typer.manual(node, name, ns)
199
200 - def skip(self, content):
201 """ 202 Get whether to skip this I{content}. 203 Should be skipped when the content is optional 204 and either the value=None or the value is an empty list. 205 @param content: The content to skip. 206 @type content: L{Object} 207 @return: True if content is to be skipped. 208 @rtype: bool 209 """ 210 if self.optional(content): 211 v = content.value 212 if v is None: 213 return True 214 if isinstance(v, (list,tuple)) and len(v) == 0: 215 return True 216 return False
217
218 - def optional(self, content):
219 if content.type.optional(): 220 return True 221 for a in content.ancestry: 222 if a.optional(): 223 return True 224 return False
225
226 - def translate(self, content):
227 """ 228 Translate using the XSD type information. 229 Python I{dict} is translated to a suds object. Most 230 importantly, primative values are translated from python 231 types to XML types using the XSD type. 232 @param content: The content to translate. 233 @type content: L{Object} 234 @return: self 235 @rtype: L{Typed} 236 """ 237 v = content.value 238 if v is None: 239 return 240 if isinstance(v, dict): 241 cls = content.real.name 242 content.value = Factory.object(cls, v) 243 md = content.value.__metadata__ 244 md.sxtype = content.type 245 return 246 v = content.real.translate(v, False) 247 content.value = v 248 return self
249
250 - def sort(self, content):
251 """ 252 Sort suds object attributes based on ordering defined 253 in the XSD type information. 254 @param content: The content to sort. 255 @type content: L{Object} 256 @return: self 257 @rtype: L{Typed} 258 """ 259 v = content.value 260 if isinstance(v, Object): 261 md = v.__metadata__ 262 md.ordering = self.ordering(content.real) 263 return self
264
265 - def ordering(self, type):
266 """ 267 Get the attribute ordering defined in the specified 268 XSD type information. 269 @param type: An XSD type object. 270 @type type: SchemaObject 271 @return: An ordered list of attribute names. 272 @rtype: list 273 """ 274 result = [] 275 for child, ancestry in type.resolve(): 276 name = child.name 277 if child.name is None: 278 continue 279 if child.isattr(): 280 name = '_%s' % child.name 281 result.append(name) 282 return result
283 284
285 -class Literal(Typed):
286 """ 287 A I{literal} marshaller. 288 This marshaller is semi-typed as needed to support both 289 I{document/literal} and I{rpc/literal} soap message styles. 290 """ 291 pass
292