Home | Trees | Indices | Help |
---|
|
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 4446 """ 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 """ 55283 284 29257 """ 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 7173 # 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 True108110 # 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()116118 # 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))124126 # 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)139141 # 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 node154156 # 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()162164 # 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 default174176 if content.type.optional(): 177 return True 178 for a in content.ancestry: 179 if a.optional(): 180 return True 181 return False182184 # 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)199201 """ 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 False217219 if content.type.optional(): 220 return True 221 for a in content.ancestry: 222 if a.optional(): 223 return True 224 return False225227 """ 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 self249251 """ 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 self264266 """ 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
Home | Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 on Mon Mar 21 14:39:10 2011 | http://epydoc.sourceforge.net |