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.sax
19 import xml.sax.handler
20 import pyxb.namespace
21 import pyxb.utils.saxutils
22 import pyxb.utils.saxdom
23 import pyxb.utils.utility
24 import basis
25 from pyxb.namespace.builtin import XMLSchema_instance as XSI
26
28 """State required to generate bindings for a specific element.
29
30 If the document being parsed includes references to unrecognized elements,
31 a DOM instance of the element and its content is created and treated as a
32 wildcard element.
33 """
34
35
36 __XSINilTuple = XSI.nil.uriTuple()
37
38
39
40
41
42
43
44
45 __bindingInstance = None
46
47
48 __elementBinding = None
49
51 """Record the binding to be used for this element.
52
53 Generally ignored, except at the top level this is the only way to
54 associate a binding instance created from an xsi:type description with
55 a specific element."""
56 self.__elementBinding = element_binding
57
58
60 """The nearest enclosing complex type definition, as used for
61 resolving local element/attribute names.
62
63 @return: An instance of L{basis.complexTypeDefinition}, or C{None} if
64 the element is top-level
65 """
66 return self.__enclosingCTD
67 __enclosingCTD = None
68
69
70
71
72 __delayedConstructor = None
73
74
75
76 __attributes = None
77
78
79 __domDocument = None
80
81 __domDepth = None
82
92
94 """Set the enclosing complex type definition for this element.
95
96 @param enclosing_ctd: The scope for a local element.
97 @type enclosing_ctd: L{basis.complexTypeDefinition}
98 @return: C{self}
99 """
100 self.__enclosingCTD = enclosing_ctd
101
102
133
136
146
156
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 self.__attributes = attrs
202 else:
203 self.__constructElement(new_object_factory, attrs)
204 return self.__bindingInstance
205
207 """Perform any end-of-element processing.
208
209 For simple type instances, this creates the binding instance.
210 @return: The generated binding instance
211 """
212 if self.__delayedConstructor is not None:
213 args = []
214 for (content, element_use, maybe_element) in self.__content:
215 assert not maybe_element
216 assert element_use is None
217 assert isinstance(content, basestring)
218 args.append(content)
219 assert 1 >= len(args), 'Unexpected STD content %s' % (args,)
220 self.__constructElement(self.__delayedConstructor, self.__attributes, args)
221 else:
222
223 for (content, element_use, maybe_element) in self.__content:
224 self.__bindingInstance.append(content, element_use, maybe_element, require_validation=pyxb._ParsingRequiresValid)
225 parent_state = self.parentState()
226 if parent_state is not None:
227 parent_state.addElementContent(self.__bindingInstance, self.__elementUse)
228
229 if self.__bindingInstance._element() is None:
230 self.__bindingInstance._setElement(self.__elementBinding)
231 if pyxb._ParsingRequiresValid:
232 self.__bindingInstance.validateBinding()
233 return self.__bindingInstance
234
236 """A SAX handler class which generates a binding instance for a document
237 through a streaming parser.
238
239 An example of using this to parse the document held in the string C{xmls} is::
240
241 import pyxb.binding.saxer
242 import StringIO
243
244 saxer = pyxb.binding.saxer.make_parser()
245 handler = saxer.getContentHandler()
246 saxer.parse(StringIO.StringIO(xml))
247 instance = handler.rootObject()
248
249 """
250
251
252 __trace = False
253
254
255 __XSITypeTuple = XSI.type.uriTuple()
256
257 __domHandler = None
258 __domDepth = None
259
261 """Return the binding object corresponding to the top-most
262 element in the document
263
264 @return: An instance of L{basis._TypeBinding_mixin} (most usually a
265 L{basis.complexTypeDefinition}.
266
267 @raise pyxb.UnrecognizedElementError: No binding could be found to
268 match the top-level element in the document."""
269 if not isinstance(self.__rootObject, basis._TypeBinding_mixin):
270
271 raise pyxb.UnrecognizedElementError(dom_node=self.__rootObject)
272 return self.__rootObject
273 __rootObject = None
274
276 """Reset the state of the handler in preparation for processing a new
277 document.
278
279 @return: C{self}
280 """
281 super(PyXBSAXHandler, self).reset()
282 self.__rootObject = None
283 return self
284
286 """Create a parser instance for converting XML to bindings.
287
288 @keyword element_state_constructor: Overridden with the value
289 L{_SAXElementState} before invoking the L{superclass
290 constructor<pyxb.utils.saxutils.BaseSAXHandler.__init__>}.
291 """
292
293 kw.setdefault('element_state_constructor', _SAXElementState)
294 super(PyXBSAXHandler, self).__init__(**kw)
295 self.reset()
296
298 (this_state, parent_state, ns_ctx, name_en) = super(PyXBSAXHandler, self).startElementNS(name, qname, attrs)
299
300
301 if this_state.inDOMMode():
302 return this_state.startDOMElement(attrs)
303
304
305
306 if parent_state.enclosingCTD() is not None:
307 (element_binding, element_use) = parent_state.enclosingCTD()._ElementBindingUseForName(name_en)
308 else:
309 element_use = None
310 element_binding = name_en.elementBinding()
311 this_state.setElementBinding(element_binding)
312
313
314
315
316 if (element_use is not None) and (element_binding is None):
317 assert self.__rootObject is not None
318 element_binding = element_use.elementBinding()
319 assert element_binding is not None
320
321
322 type_class = None
323 if element_binding is not None:
324 element_binding = element_binding.elementForName(name)
325 type_class = element_binding.typeDefinition()
326
327
328 if attrs.has_key(self.__XSITypeTuple):
329 (did_replace, type_class) = XSI._InterpretTypeAttribute(attrs.getValue(self.__XSITypeTuple), ns_ctx, None, type_class)
330 if did_replace:
331 element_binding = None
332
333 if type_class is None:
334
335
336
337 return this_state.enterDOMMode(attrs)
338
339 if element_binding is not None:
340
341
342 new_object_factory = element_binding
343 else:
344 new_object_factory = type_class.Factory
345
346
347
348 assert type_class is not None
349 if issubclass(type_class, pyxb.binding.basis.complexTypeDefinition):
350 this_state.setEnclosingCTD(type_class)
351 else:
352 this_state.setEnclosingCTD(parent_state.enclosingCTD())
353
354
355
356 binding_object = this_state.startBindingElement(type_class, new_object_factory, element_use, attrs)
357
358
359
360 if self.__rootObject is None:
361 self.__rootObject = binding_object
362
385
387 """Extend L{pyxb.utils.saxutils.make_parser} to change the default
388 C{content_handler_constructor} to be L{PyXBSAXHandler}.
389 """
390 kw.setdefault('content_handler_constructor', PyXBSAXHandler)
391 return pyxb.utils.saxutils.make_parser(*args, **kw)
392
393
394
395
396