1*cda5da8dSAndroid Build Coastguard Worker"""\ 2*cda5da8dSAndroid Build Coastguard WorkerA library of useful helper classes to the SAX classes, for the 3*cda5da8dSAndroid Build Coastguard Workerconvenience of application and driver writers. 4*cda5da8dSAndroid Build Coastguard Worker""" 5*cda5da8dSAndroid Build Coastguard Worker 6*cda5da8dSAndroid Build Coastguard Workerimport os, urllib.parse, urllib.request 7*cda5da8dSAndroid Build Coastguard Workerimport io 8*cda5da8dSAndroid Build Coastguard Workerimport codecs 9*cda5da8dSAndroid Build Coastguard Workerfrom . import handler 10*cda5da8dSAndroid Build Coastguard Workerfrom . import xmlreader 11*cda5da8dSAndroid Build Coastguard Worker 12*cda5da8dSAndroid Build Coastguard Workerdef __dict_replace(s, d): 13*cda5da8dSAndroid Build Coastguard Worker """Replace substrings of a string using a dictionary.""" 14*cda5da8dSAndroid Build Coastguard Worker for key, value in d.items(): 15*cda5da8dSAndroid Build Coastguard Worker s = s.replace(key, value) 16*cda5da8dSAndroid Build Coastguard Worker return s 17*cda5da8dSAndroid Build Coastguard Worker 18*cda5da8dSAndroid Build Coastguard Workerdef escape(data, entities={}): 19*cda5da8dSAndroid Build Coastguard Worker """Escape &, <, and > in a string of data. 20*cda5da8dSAndroid Build Coastguard Worker 21*cda5da8dSAndroid Build Coastguard Worker You can escape other strings of data by passing a dictionary as 22*cda5da8dSAndroid Build Coastguard Worker the optional entities parameter. The keys and values must all be 23*cda5da8dSAndroid Build Coastguard Worker strings; each key will be replaced with its corresponding value. 24*cda5da8dSAndroid Build Coastguard Worker """ 25*cda5da8dSAndroid Build Coastguard Worker 26*cda5da8dSAndroid Build Coastguard Worker # must do ampersand first 27*cda5da8dSAndroid Build Coastguard Worker data = data.replace("&", "&") 28*cda5da8dSAndroid Build Coastguard Worker data = data.replace(">", ">") 29*cda5da8dSAndroid Build Coastguard Worker data = data.replace("<", "<") 30*cda5da8dSAndroid Build Coastguard Worker if entities: 31*cda5da8dSAndroid Build Coastguard Worker data = __dict_replace(data, entities) 32*cda5da8dSAndroid Build Coastguard Worker return data 33*cda5da8dSAndroid Build Coastguard Worker 34*cda5da8dSAndroid Build Coastguard Workerdef unescape(data, entities={}): 35*cda5da8dSAndroid Build Coastguard Worker """Unescape &, <, and > in a string of data. 36*cda5da8dSAndroid Build Coastguard Worker 37*cda5da8dSAndroid Build Coastguard Worker You can unescape other strings of data by passing a dictionary as 38*cda5da8dSAndroid Build Coastguard Worker the optional entities parameter. The keys and values must all be 39*cda5da8dSAndroid Build Coastguard Worker strings; each key will be replaced with its corresponding value. 40*cda5da8dSAndroid Build Coastguard Worker """ 41*cda5da8dSAndroid Build Coastguard Worker data = data.replace("<", "<") 42*cda5da8dSAndroid Build Coastguard Worker data = data.replace(">", ">") 43*cda5da8dSAndroid Build Coastguard Worker if entities: 44*cda5da8dSAndroid Build Coastguard Worker data = __dict_replace(data, entities) 45*cda5da8dSAndroid Build Coastguard Worker # must do ampersand last 46*cda5da8dSAndroid Build Coastguard Worker return data.replace("&", "&") 47*cda5da8dSAndroid Build Coastguard Worker 48*cda5da8dSAndroid Build Coastguard Workerdef quoteattr(data, entities={}): 49*cda5da8dSAndroid Build Coastguard Worker """Escape and quote an attribute value. 50*cda5da8dSAndroid Build Coastguard Worker 51*cda5da8dSAndroid Build Coastguard Worker Escape &, <, and > in a string of data, then quote it for use as 52*cda5da8dSAndroid Build Coastguard Worker an attribute value. The \" character will be escaped as well, if 53*cda5da8dSAndroid Build Coastguard Worker necessary. 54*cda5da8dSAndroid Build Coastguard Worker 55*cda5da8dSAndroid Build Coastguard Worker You can escape other strings of data by passing a dictionary as 56*cda5da8dSAndroid Build Coastguard Worker the optional entities parameter. The keys and values must all be 57*cda5da8dSAndroid Build Coastguard Worker strings; each key will be replaced with its corresponding value. 58*cda5da8dSAndroid Build Coastguard Worker """ 59*cda5da8dSAndroid Build Coastguard Worker entities = {**entities, '\n': ' ', '\r': ' ', '\t':'	'} 60*cda5da8dSAndroid Build Coastguard Worker data = escape(data, entities) 61*cda5da8dSAndroid Build Coastguard Worker if '"' in data: 62*cda5da8dSAndroid Build Coastguard Worker if "'" in data: 63*cda5da8dSAndroid Build Coastguard Worker data = '"%s"' % data.replace('"', """) 64*cda5da8dSAndroid Build Coastguard Worker else: 65*cda5da8dSAndroid Build Coastguard Worker data = "'%s'" % data 66*cda5da8dSAndroid Build Coastguard Worker else: 67*cda5da8dSAndroid Build Coastguard Worker data = '"%s"' % data 68*cda5da8dSAndroid Build Coastguard Worker return data 69*cda5da8dSAndroid Build Coastguard Worker 70*cda5da8dSAndroid Build Coastguard Worker 71*cda5da8dSAndroid Build Coastguard Workerdef _gettextwriter(out, encoding): 72*cda5da8dSAndroid Build Coastguard Worker if out is None: 73*cda5da8dSAndroid Build Coastguard Worker import sys 74*cda5da8dSAndroid Build Coastguard Worker return sys.stdout 75*cda5da8dSAndroid Build Coastguard Worker 76*cda5da8dSAndroid Build Coastguard Worker if isinstance(out, io.TextIOBase): 77*cda5da8dSAndroid Build Coastguard Worker # use a text writer as is 78*cda5da8dSAndroid Build Coastguard Worker return out 79*cda5da8dSAndroid Build Coastguard Worker 80*cda5da8dSAndroid Build Coastguard Worker if isinstance(out, (codecs.StreamWriter, codecs.StreamReaderWriter)): 81*cda5da8dSAndroid Build Coastguard Worker # use a codecs stream writer as is 82*cda5da8dSAndroid Build Coastguard Worker return out 83*cda5da8dSAndroid Build Coastguard Worker 84*cda5da8dSAndroid Build Coastguard Worker # wrap a binary writer with TextIOWrapper 85*cda5da8dSAndroid Build Coastguard Worker if isinstance(out, io.RawIOBase): 86*cda5da8dSAndroid Build Coastguard Worker # Keep the original file open when the TextIOWrapper is 87*cda5da8dSAndroid Build Coastguard Worker # destroyed 88*cda5da8dSAndroid Build Coastguard Worker class _wrapper: 89*cda5da8dSAndroid Build Coastguard Worker __class__ = out.__class__ 90*cda5da8dSAndroid Build Coastguard Worker def __getattr__(self, name): 91*cda5da8dSAndroid Build Coastguard Worker return getattr(out, name) 92*cda5da8dSAndroid Build Coastguard Worker buffer = _wrapper() 93*cda5da8dSAndroid Build Coastguard Worker buffer.close = lambda: None 94*cda5da8dSAndroid Build Coastguard Worker else: 95*cda5da8dSAndroid Build Coastguard Worker # This is to handle passed objects that aren't in the 96*cda5da8dSAndroid Build Coastguard Worker # IOBase hierarchy, but just have a write method 97*cda5da8dSAndroid Build Coastguard Worker buffer = io.BufferedIOBase() 98*cda5da8dSAndroid Build Coastguard Worker buffer.writable = lambda: True 99*cda5da8dSAndroid Build Coastguard Worker buffer.write = out.write 100*cda5da8dSAndroid Build Coastguard Worker try: 101*cda5da8dSAndroid Build Coastguard Worker # TextIOWrapper uses this methods to determine 102*cda5da8dSAndroid Build Coastguard Worker # if BOM (for UTF-16, etc) should be added 103*cda5da8dSAndroid Build Coastguard Worker buffer.seekable = out.seekable 104*cda5da8dSAndroid Build Coastguard Worker buffer.tell = out.tell 105*cda5da8dSAndroid Build Coastguard Worker except AttributeError: 106*cda5da8dSAndroid Build Coastguard Worker pass 107*cda5da8dSAndroid Build Coastguard Worker return io.TextIOWrapper(buffer, encoding=encoding, 108*cda5da8dSAndroid Build Coastguard Worker errors='xmlcharrefreplace', 109*cda5da8dSAndroid Build Coastguard Worker newline='\n', 110*cda5da8dSAndroid Build Coastguard Worker write_through=True) 111*cda5da8dSAndroid Build Coastguard Worker 112*cda5da8dSAndroid Build Coastguard Workerclass XMLGenerator(handler.ContentHandler): 113*cda5da8dSAndroid Build Coastguard Worker 114*cda5da8dSAndroid Build Coastguard Worker def __init__(self, out=None, encoding="iso-8859-1", short_empty_elements=False): 115*cda5da8dSAndroid Build Coastguard Worker handler.ContentHandler.__init__(self) 116*cda5da8dSAndroid Build Coastguard Worker out = _gettextwriter(out, encoding) 117*cda5da8dSAndroid Build Coastguard Worker self._write = out.write 118*cda5da8dSAndroid Build Coastguard Worker self._flush = out.flush 119*cda5da8dSAndroid Build Coastguard Worker self._ns_contexts = [{}] # contains uri -> prefix dicts 120*cda5da8dSAndroid Build Coastguard Worker self._current_context = self._ns_contexts[-1] 121*cda5da8dSAndroid Build Coastguard Worker self._undeclared_ns_maps = [] 122*cda5da8dSAndroid Build Coastguard Worker self._encoding = encoding 123*cda5da8dSAndroid Build Coastguard Worker self._short_empty_elements = short_empty_elements 124*cda5da8dSAndroid Build Coastguard Worker self._pending_start_element = False 125*cda5da8dSAndroid Build Coastguard Worker 126*cda5da8dSAndroid Build Coastguard Worker def _qname(self, name): 127*cda5da8dSAndroid Build Coastguard Worker """Builds a qualified name from a (ns_url, localname) pair""" 128*cda5da8dSAndroid Build Coastguard Worker if name[0]: 129*cda5da8dSAndroid Build Coastguard Worker # Per http://www.w3.org/XML/1998/namespace, The 'xml' prefix is 130*cda5da8dSAndroid Build Coastguard Worker # bound by definition to http://www.w3.org/XML/1998/namespace. It 131*cda5da8dSAndroid Build Coastguard Worker # does not need to be declared and will not usually be found in 132*cda5da8dSAndroid Build Coastguard Worker # self._current_context. 133*cda5da8dSAndroid Build Coastguard Worker if 'http://www.w3.org/XML/1998/namespace' == name[0]: 134*cda5da8dSAndroid Build Coastguard Worker return 'xml:' + name[1] 135*cda5da8dSAndroid Build Coastguard Worker # The name is in a non-empty namespace 136*cda5da8dSAndroid Build Coastguard Worker prefix = self._current_context[name[0]] 137*cda5da8dSAndroid Build Coastguard Worker if prefix: 138*cda5da8dSAndroid Build Coastguard Worker # If it is not the default namespace, prepend the prefix 139*cda5da8dSAndroid Build Coastguard Worker return prefix + ":" + name[1] 140*cda5da8dSAndroid Build Coastguard Worker # Return the unqualified name 141*cda5da8dSAndroid Build Coastguard Worker return name[1] 142*cda5da8dSAndroid Build Coastguard Worker 143*cda5da8dSAndroid Build Coastguard Worker def _finish_pending_start_element(self,endElement=False): 144*cda5da8dSAndroid Build Coastguard Worker if self._pending_start_element: 145*cda5da8dSAndroid Build Coastguard Worker self._write('>') 146*cda5da8dSAndroid Build Coastguard Worker self._pending_start_element = False 147*cda5da8dSAndroid Build Coastguard Worker 148*cda5da8dSAndroid Build Coastguard Worker # ContentHandler methods 149*cda5da8dSAndroid Build Coastguard Worker 150*cda5da8dSAndroid Build Coastguard Worker def startDocument(self): 151*cda5da8dSAndroid Build Coastguard Worker self._write('<?xml version="1.0" encoding="%s"?>\n' % 152*cda5da8dSAndroid Build Coastguard Worker self._encoding) 153*cda5da8dSAndroid Build Coastguard Worker 154*cda5da8dSAndroid Build Coastguard Worker def endDocument(self): 155*cda5da8dSAndroid Build Coastguard Worker self._flush() 156*cda5da8dSAndroid Build Coastguard Worker 157*cda5da8dSAndroid Build Coastguard Worker def startPrefixMapping(self, prefix, uri): 158*cda5da8dSAndroid Build Coastguard Worker self._ns_contexts.append(self._current_context.copy()) 159*cda5da8dSAndroid Build Coastguard Worker self._current_context[uri] = prefix 160*cda5da8dSAndroid Build Coastguard Worker self._undeclared_ns_maps.append((prefix, uri)) 161*cda5da8dSAndroid Build Coastguard Worker 162*cda5da8dSAndroid Build Coastguard Worker def endPrefixMapping(self, prefix): 163*cda5da8dSAndroid Build Coastguard Worker self._current_context = self._ns_contexts[-1] 164*cda5da8dSAndroid Build Coastguard Worker del self._ns_contexts[-1] 165*cda5da8dSAndroid Build Coastguard Worker 166*cda5da8dSAndroid Build Coastguard Worker def startElement(self, name, attrs): 167*cda5da8dSAndroid Build Coastguard Worker self._finish_pending_start_element() 168*cda5da8dSAndroid Build Coastguard Worker self._write('<' + name) 169*cda5da8dSAndroid Build Coastguard Worker for (name, value) in attrs.items(): 170*cda5da8dSAndroid Build Coastguard Worker self._write(' %s=%s' % (name, quoteattr(value))) 171*cda5da8dSAndroid Build Coastguard Worker if self._short_empty_elements: 172*cda5da8dSAndroid Build Coastguard Worker self._pending_start_element = True 173*cda5da8dSAndroid Build Coastguard Worker else: 174*cda5da8dSAndroid Build Coastguard Worker self._write(">") 175*cda5da8dSAndroid Build Coastguard Worker 176*cda5da8dSAndroid Build Coastguard Worker def endElement(self, name): 177*cda5da8dSAndroid Build Coastguard Worker if self._pending_start_element: 178*cda5da8dSAndroid Build Coastguard Worker self._write('/>') 179*cda5da8dSAndroid Build Coastguard Worker self._pending_start_element = False 180*cda5da8dSAndroid Build Coastguard Worker else: 181*cda5da8dSAndroid Build Coastguard Worker self._write('</%s>' % name) 182*cda5da8dSAndroid Build Coastguard Worker 183*cda5da8dSAndroid Build Coastguard Worker def startElementNS(self, name, qname, attrs): 184*cda5da8dSAndroid Build Coastguard Worker self._finish_pending_start_element() 185*cda5da8dSAndroid Build Coastguard Worker self._write('<' + self._qname(name)) 186*cda5da8dSAndroid Build Coastguard Worker 187*cda5da8dSAndroid Build Coastguard Worker for prefix, uri in self._undeclared_ns_maps: 188*cda5da8dSAndroid Build Coastguard Worker if prefix: 189*cda5da8dSAndroid Build Coastguard Worker self._write(' xmlns:%s="%s"' % (prefix, uri)) 190*cda5da8dSAndroid Build Coastguard Worker else: 191*cda5da8dSAndroid Build Coastguard Worker self._write(' xmlns="%s"' % uri) 192*cda5da8dSAndroid Build Coastguard Worker self._undeclared_ns_maps = [] 193*cda5da8dSAndroid Build Coastguard Worker 194*cda5da8dSAndroid Build Coastguard Worker for (name, value) in attrs.items(): 195*cda5da8dSAndroid Build Coastguard Worker self._write(' %s=%s' % (self._qname(name), quoteattr(value))) 196*cda5da8dSAndroid Build Coastguard Worker if self._short_empty_elements: 197*cda5da8dSAndroid Build Coastguard Worker self._pending_start_element = True 198*cda5da8dSAndroid Build Coastguard Worker else: 199*cda5da8dSAndroid Build Coastguard Worker self._write(">") 200*cda5da8dSAndroid Build Coastguard Worker 201*cda5da8dSAndroid Build Coastguard Worker def endElementNS(self, name, qname): 202*cda5da8dSAndroid Build Coastguard Worker if self._pending_start_element: 203*cda5da8dSAndroid Build Coastguard Worker self._write('/>') 204*cda5da8dSAndroid Build Coastguard Worker self._pending_start_element = False 205*cda5da8dSAndroid Build Coastguard Worker else: 206*cda5da8dSAndroid Build Coastguard Worker self._write('</%s>' % self._qname(name)) 207*cda5da8dSAndroid Build Coastguard Worker 208*cda5da8dSAndroid Build Coastguard Worker def characters(self, content): 209*cda5da8dSAndroid Build Coastguard Worker if content: 210*cda5da8dSAndroid Build Coastguard Worker self._finish_pending_start_element() 211*cda5da8dSAndroid Build Coastguard Worker if not isinstance(content, str): 212*cda5da8dSAndroid Build Coastguard Worker content = str(content, self._encoding) 213*cda5da8dSAndroid Build Coastguard Worker self._write(escape(content)) 214*cda5da8dSAndroid Build Coastguard Worker 215*cda5da8dSAndroid Build Coastguard Worker def ignorableWhitespace(self, content): 216*cda5da8dSAndroid Build Coastguard Worker if content: 217*cda5da8dSAndroid Build Coastguard Worker self._finish_pending_start_element() 218*cda5da8dSAndroid Build Coastguard Worker if not isinstance(content, str): 219*cda5da8dSAndroid Build Coastguard Worker content = str(content, self._encoding) 220*cda5da8dSAndroid Build Coastguard Worker self._write(content) 221*cda5da8dSAndroid Build Coastguard Worker 222*cda5da8dSAndroid Build Coastguard Worker def processingInstruction(self, target, data): 223*cda5da8dSAndroid Build Coastguard Worker self._finish_pending_start_element() 224*cda5da8dSAndroid Build Coastguard Worker self._write('<?%s %s?>' % (target, data)) 225*cda5da8dSAndroid Build Coastguard Worker 226*cda5da8dSAndroid Build Coastguard Worker 227*cda5da8dSAndroid Build Coastguard Workerclass XMLFilterBase(xmlreader.XMLReader): 228*cda5da8dSAndroid Build Coastguard Worker """This class is designed to sit between an XMLReader and the 229*cda5da8dSAndroid Build Coastguard Worker client application's event handlers. By default, it does nothing 230*cda5da8dSAndroid Build Coastguard Worker but pass requests up to the reader and events on to the handlers 231*cda5da8dSAndroid Build Coastguard Worker unmodified, but subclasses can override specific methods to modify 232*cda5da8dSAndroid Build Coastguard Worker the event stream or the configuration requests as they pass 233*cda5da8dSAndroid Build Coastguard Worker through.""" 234*cda5da8dSAndroid Build Coastguard Worker 235*cda5da8dSAndroid Build Coastguard Worker def __init__(self, parent = None): 236*cda5da8dSAndroid Build Coastguard Worker xmlreader.XMLReader.__init__(self) 237*cda5da8dSAndroid Build Coastguard Worker self._parent = parent 238*cda5da8dSAndroid Build Coastguard Worker 239*cda5da8dSAndroid Build Coastguard Worker # ErrorHandler methods 240*cda5da8dSAndroid Build Coastguard Worker 241*cda5da8dSAndroid Build Coastguard Worker def error(self, exception): 242*cda5da8dSAndroid Build Coastguard Worker self._err_handler.error(exception) 243*cda5da8dSAndroid Build Coastguard Worker 244*cda5da8dSAndroid Build Coastguard Worker def fatalError(self, exception): 245*cda5da8dSAndroid Build Coastguard Worker self._err_handler.fatalError(exception) 246*cda5da8dSAndroid Build Coastguard Worker 247*cda5da8dSAndroid Build Coastguard Worker def warning(self, exception): 248*cda5da8dSAndroid Build Coastguard Worker self._err_handler.warning(exception) 249*cda5da8dSAndroid Build Coastguard Worker 250*cda5da8dSAndroid Build Coastguard Worker # ContentHandler methods 251*cda5da8dSAndroid Build Coastguard Worker 252*cda5da8dSAndroid Build Coastguard Worker def setDocumentLocator(self, locator): 253*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.setDocumentLocator(locator) 254*cda5da8dSAndroid Build Coastguard Worker 255*cda5da8dSAndroid Build Coastguard Worker def startDocument(self): 256*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.startDocument() 257*cda5da8dSAndroid Build Coastguard Worker 258*cda5da8dSAndroid Build Coastguard Worker def endDocument(self): 259*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.endDocument() 260*cda5da8dSAndroid Build Coastguard Worker 261*cda5da8dSAndroid Build Coastguard Worker def startPrefixMapping(self, prefix, uri): 262*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.startPrefixMapping(prefix, uri) 263*cda5da8dSAndroid Build Coastguard Worker 264*cda5da8dSAndroid Build Coastguard Worker def endPrefixMapping(self, prefix): 265*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.endPrefixMapping(prefix) 266*cda5da8dSAndroid Build Coastguard Worker 267*cda5da8dSAndroid Build Coastguard Worker def startElement(self, name, attrs): 268*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.startElement(name, attrs) 269*cda5da8dSAndroid Build Coastguard Worker 270*cda5da8dSAndroid Build Coastguard Worker def endElement(self, name): 271*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.endElement(name) 272*cda5da8dSAndroid Build Coastguard Worker 273*cda5da8dSAndroid Build Coastguard Worker def startElementNS(self, name, qname, attrs): 274*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.startElementNS(name, qname, attrs) 275*cda5da8dSAndroid Build Coastguard Worker 276*cda5da8dSAndroid Build Coastguard Worker def endElementNS(self, name, qname): 277*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.endElementNS(name, qname) 278*cda5da8dSAndroid Build Coastguard Worker 279*cda5da8dSAndroid Build Coastguard Worker def characters(self, content): 280*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.characters(content) 281*cda5da8dSAndroid Build Coastguard Worker 282*cda5da8dSAndroid Build Coastguard Worker def ignorableWhitespace(self, chars): 283*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.ignorableWhitespace(chars) 284*cda5da8dSAndroid Build Coastguard Worker 285*cda5da8dSAndroid Build Coastguard Worker def processingInstruction(self, target, data): 286*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.processingInstruction(target, data) 287*cda5da8dSAndroid Build Coastguard Worker 288*cda5da8dSAndroid Build Coastguard Worker def skippedEntity(self, name): 289*cda5da8dSAndroid Build Coastguard Worker self._cont_handler.skippedEntity(name) 290*cda5da8dSAndroid Build Coastguard Worker 291*cda5da8dSAndroid Build Coastguard Worker # DTDHandler methods 292*cda5da8dSAndroid Build Coastguard Worker 293*cda5da8dSAndroid Build Coastguard Worker def notationDecl(self, name, publicId, systemId): 294*cda5da8dSAndroid Build Coastguard Worker self._dtd_handler.notationDecl(name, publicId, systemId) 295*cda5da8dSAndroid Build Coastguard Worker 296*cda5da8dSAndroid Build Coastguard Worker def unparsedEntityDecl(self, name, publicId, systemId, ndata): 297*cda5da8dSAndroid Build Coastguard Worker self._dtd_handler.unparsedEntityDecl(name, publicId, systemId, ndata) 298*cda5da8dSAndroid Build Coastguard Worker 299*cda5da8dSAndroid Build Coastguard Worker # EntityResolver methods 300*cda5da8dSAndroid Build Coastguard Worker 301*cda5da8dSAndroid Build Coastguard Worker def resolveEntity(self, publicId, systemId): 302*cda5da8dSAndroid Build Coastguard Worker return self._ent_handler.resolveEntity(publicId, systemId) 303*cda5da8dSAndroid Build Coastguard Worker 304*cda5da8dSAndroid Build Coastguard Worker # XMLReader methods 305*cda5da8dSAndroid Build Coastguard Worker 306*cda5da8dSAndroid Build Coastguard Worker def parse(self, source): 307*cda5da8dSAndroid Build Coastguard Worker self._parent.setContentHandler(self) 308*cda5da8dSAndroid Build Coastguard Worker self._parent.setErrorHandler(self) 309*cda5da8dSAndroid Build Coastguard Worker self._parent.setEntityResolver(self) 310*cda5da8dSAndroid Build Coastguard Worker self._parent.setDTDHandler(self) 311*cda5da8dSAndroid Build Coastguard Worker self._parent.parse(source) 312*cda5da8dSAndroid Build Coastguard Worker 313*cda5da8dSAndroid Build Coastguard Worker def setLocale(self, locale): 314*cda5da8dSAndroid Build Coastguard Worker self._parent.setLocale(locale) 315*cda5da8dSAndroid Build Coastguard Worker 316*cda5da8dSAndroid Build Coastguard Worker def getFeature(self, name): 317*cda5da8dSAndroid Build Coastguard Worker return self._parent.getFeature(name) 318*cda5da8dSAndroid Build Coastguard Worker 319*cda5da8dSAndroid Build Coastguard Worker def setFeature(self, name, state): 320*cda5da8dSAndroid Build Coastguard Worker self._parent.setFeature(name, state) 321*cda5da8dSAndroid Build Coastguard Worker 322*cda5da8dSAndroid Build Coastguard Worker def getProperty(self, name): 323*cda5da8dSAndroid Build Coastguard Worker return self._parent.getProperty(name) 324*cda5da8dSAndroid Build Coastguard Worker 325*cda5da8dSAndroid Build Coastguard Worker def setProperty(self, name, value): 326*cda5da8dSAndroid Build Coastguard Worker self._parent.setProperty(name, value) 327*cda5da8dSAndroid Build Coastguard Worker 328*cda5da8dSAndroid Build Coastguard Worker # XMLFilter methods 329*cda5da8dSAndroid Build Coastguard Worker 330*cda5da8dSAndroid Build Coastguard Worker def getParent(self): 331*cda5da8dSAndroid Build Coastguard Worker return self._parent 332*cda5da8dSAndroid Build Coastguard Worker 333*cda5da8dSAndroid Build Coastguard Worker def setParent(self, parent): 334*cda5da8dSAndroid Build Coastguard Worker self._parent = parent 335*cda5da8dSAndroid Build Coastguard Worker 336*cda5da8dSAndroid Build Coastguard Worker# --- Utility functions 337*cda5da8dSAndroid Build Coastguard Worker 338*cda5da8dSAndroid Build Coastguard Workerdef prepare_input_source(source, base=""): 339*cda5da8dSAndroid Build Coastguard Worker """This function takes an InputSource and an optional base URL and 340*cda5da8dSAndroid Build Coastguard Worker returns a fully resolved InputSource object ready for reading.""" 341*cda5da8dSAndroid Build Coastguard Worker 342*cda5da8dSAndroid Build Coastguard Worker if isinstance(source, os.PathLike): 343*cda5da8dSAndroid Build Coastguard Worker source = os.fspath(source) 344*cda5da8dSAndroid Build Coastguard Worker if isinstance(source, str): 345*cda5da8dSAndroid Build Coastguard Worker source = xmlreader.InputSource(source) 346*cda5da8dSAndroid Build Coastguard Worker elif hasattr(source, "read"): 347*cda5da8dSAndroid Build Coastguard Worker f = source 348*cda5da8dSAndroid Build Coastguard Worker source = xmlreader.InputSource() 349*cda5da8dSAndroid Build Coastguard Worker if isinstance(f.read(0), str): 350*cda5da8dSAndroid Build Coastguard Worker source.setCharacterStream(f) 351*cda5da8dSAndroid Build Coastguard Worker else: 352*cda5da8dSAndroid Build Coastguard Worker source.setByteStream(f) 353*cda5da8dSAndroid Build Coastguard Worker if hasattr(f, "name") and isinstance(f.name, str): 354*cda5da8dSAndroid Build Coastguard Worker source.setSystemId(f.name) 355*cda5da8dSAndroid Build Coastguard Worker 356*cda5da8dSAndroid Build Coastguard Worker if source.getCharacterStream() is None and source.getByteStream() is None: 357*cda5da8dSAndroid Build Coastguard Worker sysid = source.getSystemId() 358*cda5da8dSAndroid Build Coastguard Worker basehead = os.path.dirname(os.path.normpath(base)) 359*cda5da8dSAndroid Build Coastguard Worker sysidfilename = os.path.join(basehead, sysid) 360*cda5da8dSAndroid Build Coastguard Worker if os.path.isfile(sysidfilename): 361*cda5da8dSAndroid Build Coastguard Worker source.setSystemId(sysidfilename) 362*cda5da8dSAndroid Build Coastguard Worker f = open(sysidfilename, "rb") 363*cda5da8dSAndroid Build Coastguard Worker else: 364*cda5da8dSAndroid Build Coastguard Worker source.setSystemId(urllib.parse.urljoin(base, sysid)) 365*cda5da8dSAndroid Build Coastguard Worker f = urllib.request.urlopen(source.getSystemId()) 366*cda5da8dSAndroid Build Coastguard Worker 367*cda5da8dSAndroid Build Coastguard Worker source.setByteStream(f) 368*cda5da8dSAndroid Build Coastguard Worker 369*cda5da8dSAndroid Build Coastguard Worker return source 370