[docs]classXmlEventHandler(XmlHandler):""" Event handler based on :func:`xml.etree.ElementTree.iterparse` api. :param parser: The parser instance to feed with events :param clazz: The target binding model, auto located if omitted. """__slots__=()
[docs]defparse(self,source:Any)->Any:""" Parse an XML document from a system identifier or an InputSource or directly from an xml Element or ElementTree. When source is an Element or ElementTree the handler will walk over the objects structure. When source is a system identifier or an InputSource the parser will ignore comments and recover from errors. When config process_xinclude is enabled the handler will parse the whole document and then walk down the element tree. """ifisinstance(source,etree.ElementTree):source=source.getroot()ifisinstance(source,etree.Element):ctx=iterwalk(source,{})elifself.parser.config.process_xinclude:root=etree.parse(source).getroot()# nosecbase_url=get_base_url(self.parser.config.base_url,source)loader=functools.partial(xinclude_loader,base_url=base_url)xinclude.include(root,loader=loader)ctx=iterwalk(root,{})else:ctx=etree.iterparse(source,EVENTS)# nosecreturnself.process_context(ctx)
[docs]defprocess_context(self,context:Iterable)->Any:"""Iterate context and push the events to main parser."""ns_map:Dict={}forevent,elementincontext:ifevent==EventType.START:self.parser.start(self.clazz,self.queue,self.objects,element.tag,element.attrib,self.merge_parent_namespaces(ns_map),)ns_map={}elifevent==EventType.END:self.parser.end(self.queue,self.objects,element.tag,element.text,element.tail,)element.clear()elifevent==EventType.START_NS:prefix,uri=elementns_map[prefixorNone]=urielse:raiseXmlHandlerError(f"Unhandled event: `{event}`.")returnself.objects[-1][1]ifself.objectselseNone
defiterwalk(element:etree.Element,ns_map:Dict)->Iterator[Tuple[str,Any]]:""" Walk over the element tree structure and emit start-ns/start/end events. The ElementTree doesn't preserve the original namespace prefixes, we have to generate new ones. """uri=namespaces.target_uri(element.tag)ifuriisnotNone:prefix=namespaces.load_prefix(uri,ns_map)yieldEventType.START_NS,(prefix,uri)yieldEventType.START,elementforchildinelement:yield fromiterwalk(child,ns_map)yieldEventType.END,elementdefget_base_url(base_url:Optional[str],source:Any)->Optional[str]:ifbase_url:returnbase_urlreturnsourceifisinstance(source,str)elseNonedefxinclude_loader(href:str,parse:str,encoding:Optional[str]=None,base_url:Optional[str]=None,)->Any:"""Custom loader for xinclude to support base_url argument that doesn't exist for python < 3.9."""returnxinclude.default_loader(urljoin(base_urlor"",href),parse,encoding)