1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """This module contains support for generating bindings from an XML stream
17 using a SAX parser."""
18
19 import xml.dom
20 import pyxb.namespace
21 import pyxb.utils.saxutils
22 import pyxb.utils.saxdom
23 import pyxb.utils.utility
24 from pyxb.binding import basis
25 from pyxb.namespace.builtin import XMLSchema_instance as XSI
26 import logging
27
28 _log = logging.getLogger(__name__)
29
31 """State required to generate bindings for a specific element.
32
33 If the document being parsed includes references to unrecognized elements,
34 a DOM instance of the element and its content is created and treated as a
35 wildcard element.
36 """
37
38
39 __XSINilTuple = XSI.nil.uriTuple()
40
41
42
43
44
45
46
47
48 __bindingInstance = None
49
50
51 __elementBinding = None
52
54 """Record the binding to be used for this element.
55
56 Generally ignored, except at the top level this is the only way to
57 associate a binding instance created from an xsi:type description with
58 a specific element."""
59 self.__elementBinding = element_binding
60
61
63 """The nearest enclosing complex type definition, as used for
64 resolving local element/attribute names.
65
66 @return: An instance of L{basis.complexTypeDefinition}, or C{None} if
67 the element is top-level
68 """
69 return self.__enclosingCTD
70 __enclosingCTD = None
71
72
73
74
75 __delayedConstructor = None
76
77
78
79 __attributes = None
80
81
82 __domDocument = None
83
84 __domDepth = None
85
95
97 """Set the enclosing complex type definition for this element.
98
99 @param enclosing_ctd: The scope for a local element.
100 @type enclosing_ctd: L{basis.complexTypeDefinition}
101 @return: C{self}
102 """
103 self.__enclosingCTD = enclosing_ctd
104
105
135
138
148
157
176
178 """Actions upon entering an element that will produce a binding instance.
179
180 The element use is recorded. If the type is a subclass of
181 L{basis.simpleTypeDefinition}, a delayed constructor is recorded so
182 the binding instance can be created upon completion of the element;
183 otherwise, a binding instance is created and stored. The attributes
184 are used to initialize the binding instance (now, or upon element
185 end).
186
187 @param type_class: The Python type of the binding instance
188 @type type_class: subclass of L{basis._TypeBinding_mixin}
189 @param new_object_factory: A callable object that creates an instance of the C{type_class}
190 @param element_use: The element use with which the binding instance is associated. Will be C{None} for top-level elements
191 @type element_use: L{basis.element}
192 @param attrs: The XML attributes associated with the element
193 @type attrs: C{xml.sax.xmlreader.Attributes}
194 @return: The generated binding instance, or C{None} if creation is delayed
195 """
196 self.__delayedConstructor = None
197 self.__elementUse = element_use
198 self.__attributes = attrs
199 if type_class._IsSimpleTypeContent():
200 self.__delayedConstructor = new_object_factory
201 else:
202 self.__constructElement(new_object_factory, attrs)
203 return self.__bindingInstance
204
206 """Perform any end-of-element processing.
207
208 For simple type instances, this creates the binding instance.
209 @return: The generated binding instance
210 """
211 if self.__delayedConstructor is not None:
212 args = []
213 for (content, element_use, maybe_element) in self.__content:
214 assert not maybe_element
215 assert element_use is None
216 assert isinstance(content, basestring)
217 args.append(content)
218 assert 1 >= len(args), 'Unexpected STD content %s' % (args,)
219 self.__constructElement(self.__delayedConstructor, self.__attributes, args)
220 else:
221 for (content, element_use, maybe_element) in self.__content:
222 self.__bindingInstance.append(content, element_use, maybe_element, require_validation=pyxb._ParsingRequiresValid)
223 parent_state = self.parentState()
224 if parent_state is not None:
225 parent_state.addElementContent(self.__bindingInstance, self.__elementUse)
226
227 if self.__bindingInstance._element() is None:
228 self.__bindingInstance._setElement(self.__elementBinding)
229 if pyxb._ParsingRequiresValid:
230 self.__bindingInstance.validateBinding()
231 return self.__bindingInstance
232
234 """A SAX handler class which generates a binding instance for a document
235 through a streaming parser.
236
237 An example of using this to parse the document held in the string C{xmls} is::
238
239 import pyxb.binding.saxer
240 import StringIO
241
242 saxer = pyxb.binding.saxer.make_parser()
243 handler = saxer.getContentHandler()
244 saxer.parse(StringIO.StringIO(xml))
245 instance = handler.rootObject()
246
247 """
248
249
250 __trace = False
251
252
253 __XSITypeTuple = XSI.type.uriTuple()
254
255 __domHandler = None
256 __domDepth = None
257
259 """Return the binding object corresponding to the top-most
260 element in the document
261
262 @return: An instance of L{basis._TypeBinding_mixin} (most usually a
263 L{basis.complexTypeDefinition}.
264
265 @raise pyxb.UnrecognizedElementError: No binding could be found to
266 match the top-level element in the document."""
267 if not isinstance(self.__rootObject, basis._TypeBinding_mixin):
268
269 raise pyxb.UnrecognizedElementError(dom_node=self.__rootObject)
270 return self.__rootObject
271 __rootObject = None
272
274 """Reset the state of the handler in preparation for processing a new
275 document.
276
277 @return: C{self}
278 """
279 super(PyXBSAXHandler, self).reset()
280 self.__rootObject = None
281 return self
282
284 """Create a parser instance for converting XML to bindings.
285
286 @keyword element_state_constructor: Overridden with the value
287 L{_SAXElementState} before invoking the L{superclass
288 constructor<pyxb.utils.saxutils.BaseSAXHandler.__init__>}.
289 """
290
291 kw.setdefault('element_state_constructor', _SAXElementState)
292 super(PyXBSAXHandler, self).__init__(**kw)
293 self.reset()
294
296 (this_state, parent_state, ns_ctx, name_en) = super(PyXBSAXHandler, self).startElementNS(name, qname, attrs)
297
298
299 if this_state.inDOMMode():
300 return this_state.startDOMElement(attrs)
301
302
303
304 if parent_state.enclosingCTD() is not None:
305 (element_binding, element_use) = parent_state.enclosingCTD()._ElementBindingUseForName(name_en)
306 else:
307 element_use = None
308 element_binding = name_en.elementBinding()
309 this_state.setElementBinding(element_binding)
310
311
312
313
314 if (element_use is not None) and (element_binding is None):
315 assert self.__rootObject is not None
316 element_binding = element_use.elementBinding()
317 assert element_binding is not None
318
319
320 type_class = None
321 if element_binding is not None:
322 element_binding = element_binding.elementForName(name)
323 type_class = element_binding.typeDefinition()
324
325
326 if attrs.has_key(self.__XSITypeTuple):
327 (did_replace, type_class) = XSI._InterpretTypeAttribute(attrs.getValue(self.__XSITypeTuple), ns_ctx, self.fallbackNamespace(), type_class)
328 if did_replace:
329 element_binding = None
330
331 if type_class is None:
332
333
334
335 return this_state.enterDOMMode(attrs)
336
337 if element_binding is not None:
338
339
340 new_object_factory = element_binding
341 else:
342 new_object_factory = type_class.Factory
343
344
345
346 assert type_class is not None
347 if issubclass(type_class, pyxb.binding.basis.complexTypeDefinition):
348 this_state.setEnclosingCTD(type_class)
349 else:
350 this_state.setEnclosingCTD(parent_state.enclosingCTD())
351
352
353
354 binding_object = this_state.startBindingElement(type_class, new_object_factory, element_use, attrs)
355
356
357
358 if self.__rootObject is None:
359 self.__rootObject = binding_object
360
383
385 """Extend L{pyxb.utils.saxutils.make_parser} to change the default
386 C{content_handler_constructor} to be L{PyXBSAXHandler}.
387 """
388 kw.setdefault('content_handler_constructor', PyXBSAXHandler)
389 return pyxb.utils.saxutils.make_parser(*args, **kw)
390
391
392
393
394