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