# Parser target context (ET target interface) cdef object inspect_getargspec try: from inspect import getfullargspec as inspect_getargspec except ImportError: from inspect import getargspec as inspect_getargspec class _TargetParserResult(Exception): # Admittedly, this is somewhat ugly, but it's the easiest way # to push the Python level parser result through the parser # machinery towards the API level functions def __init__(self, result): self.result = result @cython.final @cython.internal cdef class _PythonSaxParserTarget(_SaxParserTarget): cdef object _target_start cdef object _target_end cdef object _target_data cdef object _target_start_ns cdef object _target_end_ns cdef object _target_doctype cdef object _target_pi cdef object _target_comment cdef bint _start_takes_nsmap def __cinit__(self, target): cdef int event_filter event_filter = 0 self._start_takes_nsmap = 0 try: self._target_start = target.start if self._target_start is not None: event_filter |= SAX_EVENT_START except AttributeError: pass else: try: arguments = inspect_getargspec(self._target_start) if len(arguments[0]) > 3 or arguments[1] is not None: self._start_takes_nsmap = 1 except TypeError: pass try: self._target_end = target.end if self._target_end is not None: event_filter |= SAX_EVENT_END except AttributeError: pass try: self._target_start_ns = target.start_ns if self._target_start_ns is not None: event_filter |= SAX_EVENT_START_NS except AttributeError: pass try: self._target_end_ns = target.end_ns if self._target_end_ns is not None: event_filter |= SAX_EVENT_END_NS except AttributeError: pass try: self._target_data = target.data if self._target_data is not None: event_filter |= SAX_EVENT_DATA except AttributeError: pass try: self._target_doctype = target.doctype if self._target_doctype is not None: event_filter |= SAX_EVENT_DOCTYPE except AttributeError: pass try: self._target_pi = target.pi if self._target_pi is not None: event_filter |= SAX_EVENT_PI except AttributeError: pass try: self._target_comment = target.comment if self._target_comment is not None: event_filter |= SAX_EVENT_COMMENT except AttributeError: pass self._sax_event_filter = event_filter cdef _handleSaxStart(self, tag, attrib, nsmap): if self._start_takes_nsmap: return self._target_start(tag, attrib, nsmap) else: return self._target_start(tag, attrib) cdef _handleSaxEnd(self, tag): return self._target_end(tag) cdef _handleSaxStartNs(self, prefix, uri): return self._target_start_ns(prefix, uri) cdef _handleSaxEndNs(self, prefix): return self._target_end_ns(prefix) cdef int _handleSaxData(self, data) except -1: self._target_data(data) cdef int _handleSaxDoctype(self, root_tag, public_id, system_id) except -1: self._target_doctype(root_tag, public_id, system_id) cdef _handleSaxPi(self, target, data): return self._target_pi(target, data) cdef _handleSaxComment(self, comment): return self._target_comment(comment) @cython.final @cython.internal @cython.no_gc_clear # Required because parent class uses it - Cython bug. cdef class _TargetParserContext(_SaxParserContext): """This class maps SAX2 events to the ET parser target interface. """ cdef object _python_target cdef int _setTarget(self, target) except -1: self._python_target = target if not isinstance(target, _SaxParserTarget) or \ hasattr(target, '__dict__'): target = _PythonSaxParserTarget(target) self._setSaxParserTarget(target) return 0 cdef _ParserContext _copy(self): cdef _TargetParserContext context context = _ParserContext._copy(self) context._setTarget(self._python_target) return context cdef void _cleanupTargetParserContext(self, xmlDoc* result) noexcept: if self._c_ctxt.myDoc is not NULL: if self._c_ctxt.myDoc is not result and \ self._c_ctxt.myDoc._private is NULL: # no _Document proxy => orphen tree.xmlFreeDoc(self._c_ctxt.myDoc) self._c_ctxt.myDoc = NULL cdef object _handleParseResult(self, _BaseParser parser, xmlDoc* result, filename): cdef bint recover recover = parser._parse_options & xmlparser.XML_PARSE_RECOVER try: if self._has_raised(): self._cleanupTargetParserContext(result) self._raise_if_stored() if not self._c_ctxt.wellFormed and not recover: _raiseParseError(self._c_ctxt, filename, self._error_log) except: self._python_target.close() raise return self._python_target.close() cdef xmlDoc* _handleParseResultDoc(self, _BaseParser parser, xmlDoc* result, filename) except NULL: cdef bint recover recover = parser._parse_options & xmlparser.XML_PARSE_RECOVER if result is not NULL and result._private is NULL: # no _Document proxy => orphen tree.xmlFreeDoc(result) try: self._cleanupTargetParserContext(result) self._raise_if_stored() if not self._c_ctxt.wellFormed and not recover: _raiseParseError(self._c_ctxt, filename, self._error_log) except: self._python_target.close() raise parse_result = self._python_target.close() raise _TargetParserResult(parse_result)