| 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
44
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
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
71
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
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
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
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
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
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
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
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
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
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
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
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
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
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
292
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Jun 20 03:54:31 2014 | http://epydoc.sourceforge.net |