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 __bindingObject = None
46
47
49 """The nearest enclosing complex type definition, as used for
50 resolving local element/attribute names.
51
52 @return: An instance of L{basis.complexTypeDefinition}, or C{None} if
53 the element is top-level
54 """
55 return self.__enclosingCTD
56 __enclosingCTD = None
57
58
59
60
61 __delayedConstructor = None
62
63
64
65 __attributes = None
66
67
68 __domDocument = None
69
70 __domDepth = None
71
81
83 """Set the enclosing complex type definition for this element.
84
85 @param enclosing_ctd: The scope for a local element.
86 @type enclosing_ctd: L{basis.complexTypeDefinition}
87 @return: C{self}
88 """
89 self.__enclosingCTD = enclosing_ctd
90
91
122
125
135
145
165
167 """Actions upon entering an element that will produce a binding instance.
168
169 The element use is recorded. If the type is a subclass of
170 L{basis.simpleTypeDefinition}, a delayed constructor is recorded so
171 the binding instance can be created upon completion of the element;
172 otherwise, a binding instance is created and stored. The attributes
173 are used to initialize the binding instance (now, or upon element
174 end).
175
176 @param type_class: The Python type of the binding instance
177 @type type_class: subclass of L{basis._TypeBinding_mixin}
178 @param new_object_factory: A callable object that creates an instance of the C{type_class}
179 @param element_use: The element use with which the binding instance is associated. Will be C{None} for top-level elements
180 @type element_use: L{basis.element}
181 @param attrs: The XML attributes associated with the element
182 @type attrs: C{xml.sax.xmlreader.Attributes}
183 @return: The generated binding instance, or C{None} if creation is delayed
184 """
185 self.__delayedConstructor = None
186 self.__elementUse = element_use
187 self.__attributes = attrs
188 if type_class._IsSimpleTypeContent():
189 self.__delayedConstructor = new_object_factory
190 self.__attributes = attrs
191 else:
192 self.__constructElement(new_object_factory, attrs)
193 return self.__bindingObject
194
196 """Perform any end-of-element processing.
197
198 For simple type instances, this creates the binding instance.
199 @return: The generated binding instance
200 """
201 if self.__delayedConstructor is not None:
202 args = []
203 for (content, element_use, maybe_element) in self.__content:
204 assert not maybe_element
205 assert element_use is None
206 assert isinstance(content, basestring)
207 args.append(content)
208 assert 1 >= len(args), 'Unexpected STD content %s' % (args,)
209 self.__constructElement(self.__delayedConstructor, self.__attributes, args)
210 else:
211
212 for (content, element_use, maybe_element) in self.__content:
213 self.__bindingObject.append(content, element_use, maybe_element, require_validation=pyxb._ParsingRequiresValid)
214 parent_state = self.parentState()
215 if parent_state is not None:
216 parent_state.addElementContent(self.__bindingObject, self.__elementUse)
217
218 if pyxb._ParsingRequiresValid:
219 self.__bindingObject.validateBinding()
220 return self.__bindingObject
221
223 """A SAX handler class which generates a binding instance for a document
224 through a streaming parser.
225
226 An example of using this to parse the document held in the string C{xmls} is::
227
228 import pyxb.binding.saxer
229 import StringIO
230
231 saxer = pyxb.binding.saxer.make_parser()
232 handler = saxer.getContentHandler()
233 saxer.parse(StringIO.StringIO(xml))
234 instance = handler.rootObject()
235
236 """
237
238
239 __trace = False
240
241
242 __XSITypeTuple = XSI.type.uriTuple()
243
244 __domHandler = None
245 __domDepth = None
246
248 """Return the binding object corresponding to the top-most
249 element in the document
250
251 @return: An instance of L{basis._TypeBinding_mixin} (most usually a
252 L{basis.complexTypeDefinition}.
253
254 @raise pyxb.UnrecognizedElementError: No binding could be found to
255 match the top-level element in the document."""
256 if not isinstance(self.__rootObject, basis._TypeBinding_mixin):
257
258 raise pyxb.UnrecognizedElementError(dom_node=self.__rootObject)
259 return self.__rootObject
260 __rootObject = None
261
263 """Reset the state of the handler in preparation for processing a new
264 document.
265
266 @return: C{self}
267 """
268 super(PyXBSAXHandler, self).reset()
269 self.__rootObject = None
270 return self
271
273 """Create a parser instance for converting XML to bindings.
274
275 @keyword element_state_constructor: Overridden with the value
276 L{_SAXElementState} before invoking the L{superclass
277 constructor<pyxb.utils.saxutils.BaseSAXHandler.__init__>}.
278 """
279
280 kw.setdefault('element_state_constructor', _SAXElementState)
281 super(PyXBSAXHandler, self).__init__(**kw)
282 self.reset()
283
285 (this_state, parent_state, ns_ctx, name_en) = super(PyXBSAXHandler, self).startElementNS(name, qname, attrs)
286
287
288 if this_state.inDOMMode():
289 return this_state.startDOMElement(attrs)
290
291
292
293 if parent_state.enclosingCTD() is not None:
294 (element_binding, element_use) = parent_state.enclosingCTD()._ElementBindingUseForName(name_en)
295 else:
296 element_use = None
297 element_binding = name_en.elementBinding()
298
299
300
301
302 if (element_use is not None) and (element_binding is None):
303 assert self.__rootObject is not None
304 element_binding = element_use.elementBinding()
305 assert element_binding is not None
306
307
308 type_class = None
309 if element_binding is not None:
310 element_binding = element_binding.elementForName(name)
311 type_class = element_binding.typeDefinition()
312
313
314 if attrs.has_key(self.__XSITypeTuple):
315 (did_replace, type_class) = XSI._InterpretTypeAttribute(attrs.getValue(self.__XSITypeTuple), ns_ctx, None, type_class)
316 if did_replace:
317 element_binding = None
318
319 if type_class is None:
320
321
322
323 return this_state.enterDOMMode(attrs)
324
325 if element_binding is not None:
326
327
328 new_object_factory = element_binding
329 else:
330 new_object_factory = type_class.Factory
331
332
333
334 assert type_class is not None
335 if issubclass(type_class, pyxb.binding.basis.complexTypeDefinition):
336 this_state.setEnclosingCTD(type_class)
337 else:
338 this_state.setEnclosingCTD(parent_state.enclosingCTD())
339
340
341
342 binding_object = this_state.startBindingElement(type_class, new_object_factory, element_use, attrs)
343
344
345
346 if self.__rootObject is None:
347 self.__rootObject = binding_object
348
371
373 """Extend L{pyxb.utils.saxutils.make_parser} to change the default
374 C{content_handler_constructor} to be L{PyXBSAXHandler}.
375 """
376 kw.setdefault('content_handler_constructor', PyXBSAXHandler)
377 return pyxb.utils.saxutils.make_parser(*args, **kw)
378
379
380
381
382