xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/xml/sax/expatreader.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""
2*cda5da8dSAndroid Build Coastguard WorkerSAX driver for the pyexpat C module.  This driver works with
3*cda5da8dSAndroid Build Coastguard Workerpyexpat.__version__ == '2.22'.
4*cda5da8dSAndroid Build Coastguard Worker"""
5*cda5da8dSAndroid Build Coastguard Worker
6*cda5da8dSAndroid Build Coastguard Workerversion = "0.20"
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Workerfrom xml.sax._exceptions import *
9*cda5da8dSAndroid Build Coastguard Workerfrom xml.sax.handler import feature_validation, feature_namespaces
10*cda5da8dSAndroid Build Coastguard Workerfrom xml.sax.handler import feature_namespace_prefixes
11*cda5da8dSAndroid Build Coastguard Workerfrom xml.sax.handler import feature_external_ges, feature_external_pes
12*cda5da8dSAndroid Build Coastguard Workerfrom xml.sax.handler import feature_string_interning
13*cda5da8dSAndroid Build Coastguard Workerfrom xml.sax.handler import property_xml_string, property_interning_dict
14*cda5da8dSAndroid Build Coastguard Worker
15*cda5da8dSAndroid Build Coastguard Worker# xml.parsers.expat does not raise ImportError in Jython
16*cda5da8dSAndroid Build Coastguard Workerimport sys
17*cda5da8dSAndroid Build Coastguard Workerif sys.platform[:4] == "java":
18*cda5da8dSAndroid Build Coastguard Worker    raise SAXReaderNotAvailable("expat not available in Java", None)
19*cda5da8dSAndroid Build Coastguard Workerdel sys
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard Workertry:
22*cda5da8dSAndroid Build Coastguard Worker    from xml.parsers import expat
23*cda5da8dSAndroid Build Coastguard Workerexcept ImportError:
24*cda5da8dSAndroid Build Coastguard Worker    raise SAXReaderNotAvailable("expat not supported", None)
25*cda5da8dSAndroid Build Coastguard Workerelse:
26*cda5da8dSAndroid Build Coastguard Worker    if not hasattr(expat, "ParserCreate"):
27*cda5da8dSAndroid Build Coastguard Worker        raise SAXReaderNotAvailable("expat not supported", None)
28*cda5da8dSAndroid Build Coastguard Workerfrom xml.sax import xmlreader, saxutils, handler
29*cda5da8dSAndroid Build Coastguard Worker
30*cda5da8dSAndroid Build Coastguard WorkerAttributesImpl = xmlreader.AttributesImpl
31*cda5da8dSAndroid Build Coastguard WorkerAttributesNSImpl = xmlreader.AttributesNSImpl
32*cda5da8dSAndroid Build Coastguard Worker
33*cda5da8dSAndroid Build Coastguard Worker# If we're using a sufficiently recent version of Python, we can use
34*cda5da8dSAndroid Build Coastguard Worker# weak references to avoid cycles between the parser and content
35*cda5da8dSAndroid Build Coastguard Worker# handler, otherwise we'll just have to pretend.
36*cda5da8dSAndroid Build Coastguard Workertry:
37*cda5da8dSAndroid Build Coastguard Worker    import _weakref
38*cda5da8dSAndroid Build Coastguard Workerexcept ImportError:
39*cda5da8dSAndroid Build Coastguard Worker    def _mkproxy(o):
40*cda5da8dSAndroid Build Coastguard Worker        return o
41*cda5da8dSAndroid Build Coastguard Workerelse:
42*cda5da8dSAndroid Build Coastguard Worker    import weakref
43*cda5da8dSAndroid Build Coastguard Worker    _mkproxy = weakref.proxy
44*cda5da8dSAndroid Build Coastguard Worker    del weakref, _weakref
45*cda5da8dSAndroid Build Coastguard Worker
46*cda5da8dSAndroid Build Coastguard Workerclass _ClosedParser:
47*cda5da8dSAndroid Build Coastguard Worker    pass
48*cda5da8dSAndroid Build Coastguard Worker
49*cda5da8dSAndroid Build Coastguard Worker# --- ExpatLocator
50*cda5da8dSAndroid Build Coastguard Worker
51*cda5da8dSAndroid Build Coastguard Workerclass ExpatLocator(xmlreader.Locator):
52*cda5da8dSAndroid Build Coastguard Worker    """Locator for use with the ExpatParser class.
53*cda5da8dSAndroid Build Coastguard Worker
54*cda5da8dSAndroid Build Coastguard Worker    This uses a weak reference to the parser object to avoid creating
55*cda5da8dSAndroid Build Coastguard Worker    a circular reference between the parser and the content handler.
56*cda5da8dSAndroid Build Coastguard Worker    """
57*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, parser):
58*cda5da8dSAndroid Build Coastguard Worker        self._ref = _mkproxy(parser)
59*cda5da8dSAndroid Build Coastguard Worker
60*cda5da8dSAndroid Build Coastguard Worker    def getColumnNumber(self):
61*cda5da8dSAndroid Build Coastguard Worker        parser = self._ref
62*cda5da8dSAndroid Build Coastguard Worker        if parser._parser is None:
63*cda5da8dSAndroid Build Coastguard Worker            return None
64*cda5da8dSAndroid Build Coastguard Worker        return parser._parser.ErrorColumnNumber
65*cda5da8dSAndroid Build Coastguard Worker
66*cda5da8dSAndroid Build Coastguard Worker    def getLineNumber(self):
67*cda5da8dSAndroid Build Coastguard Worker        parser = self._ref
68*cda5da8dSAndroid Build Coastguard Worker        if parser._parser is None:
69*cda5da8dSAndroid Build Coastguard Worker            return 1
70*cda5da8dSAndroid Build Coastguard Worker        return parser._parser.ErrorLineNumber
71*cda5da8dSAndroid Build Coastguard Worker
72*cda5da8dSAndroid Build Coastguard Worker    def getPublicId(self):
73*cda5da8dSAndroid Build Coastguard Worker        parser = self._ref
74*cda5da8dSAndroid Build Coastguard Worker        if parser is None:
75*cda5da8dSAndroid Build Coastguard Worker            return None
76*cda5da8dSAndroid Build Coastguard Worker        return parser._source.getPublicId()
77*cda5da8dSAndroid Build Coastguard Worker
78*cda5da8dSAndroid Build Coastguard Worker    def getSystemId(self):
79*cda5da8dSAndroid Build Coastguard Worker        parser = self._ref
80*cda5da8dSAndroid Build Coastguard Worker        if parser is None:
81*cda5da8dSAndroid Build Coastguard Worker            return None
82*cda5da8dSAndroid Build Coastguard Worker        return parser._source.getSystemId()
83*cda5da8dSAndroid Build Coastguard Worker
84*cda5da8dSAndroid Build Coastguard Worker
85*cda5da8dSAndroid Build Coastguard Worker# --- ExpatParser
86*cda5da8dSAndroid Build Coastguard Worker
87*cda5da8dSAndroid Build Coastguard Workerclass ExpatParser(xmlreader.IncrementalParser, xmlreader.Locator):
88*cda5da8dSAndroid Build Coastguard Worker    """SAX driver for the pyexpat C module."""
89*cda5da8dSAndroid Build Coastguard Worker
90*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, namespaceHandling=0, bufsize=2**16-20):
91*cda5da8dSAndroid Build Coastguard Worker        xmlreader.IncrementalParser.__init__(self, bufsize)
92*cda5da8dSAndroid Build Coastguard Worker        self._source = xmlreader.InputSource()
93*cda5da8dSAndroid Build Coastguard Worker        self._parser = None
94*cda5da8dSAndroid Build Coastguard Worker        self._namespaces = namespaceHandling
95*cda5da8dSAndroid Build Coastguard Worker        self._lex_handler_prop = None
96*cda5da8dSAndroid Build Coastguard Worker        self._parsing = False
97*cda5da8dSAndroid Build Coastguard Worker        self._entity_stack = []
98*cda5da8dSAndroid Build Coastguard Worker        self._external_ges = 0
99*cda5da8dSAndroid Build Coastguard Worker        self._interning = None
100*cda5da8dSAndroid Build Coastguard Worker
101*cda5da8dSAndroid Build Coastguard Worker    # XMLReader methods
102*cda5da8dSAndroid Build Coastguard Worker
103*cda5da8dSAndroid Build Coastguard Worker    def parse(self, source):
104*cda5da8dSAndroid Build Coastguard Worker        "Parse an XML document from a URL or an InputSource."
105*cda5da8dSAndroid Build Coastguard Worker        source = saxutils.prepare_input_source(source)
106*cda5da8dSAndroid Build Coastguard Worker
107*cda5da8dSAndroid Build Coastguard Worker        self._source = source
108*cda5da8dSAndroid Build Coastguard Worker        try:
109*cda5da8dSAndroid Build Coastguard Worker            self.reset()
110*cda5da8dSAndroid Build Coastguard Worker            self._cont_handler.setDocumentLocator(ExpatLocator(self))
111*cda5da8dSAndroid Build Coastguard Worker            xmlreader.IncrementalParser.parse(self, source)
112*cda5da8dSAndroid Build Coastguard Worker        except:
113*cda5da8dSAndroid Build Coastguard Worker            # bpo-30264: Close the source on error to not leak resources:
114*cda5da8dSAndroid Build Coastguard Worker            # xml.sax.parse() doesn't give access to the underlying parser
115*cda5da8dSAndroid Build Coastguard Worker            # to the caller
116*cda5da8dSAndroid Build Coastguard Worker            self._close_source()
117*cda5da8dSAndroid Build Coastguard Worker            raise
118*cda5da8dSAndroid Build Coastguard Worker
119*cda5da8dSAndroid Build Coastguard Worker    def prepareParser(self, source):
120*cda5da8dSAndroid Build Coastguard Worker        if source.getSystemId() is not None:
121*cda5da8dSAndroid Build Coastguard Worker            self._parser.SetBase(source.getSystemId())
122*cda5da8dSAndroid Build Coastguard Worker
123*cda5da8dSAndroid Build Coastguard Worker    # Redefined setContentHandler to allow changing handlers during parsing
124*cda5da8dSAndroid Build Coastguard Worker
125*cda5da8dSAndroid Build Coastguard Worker    def setContentHandler(self, handler):
126*cda5da8dSAndroid Build Coastguard Worker        xmlreader.IncrementalParser.setContentHandler(self, handler)
127*cda5da8dSAndroid Build Coastguard Worker        if self._parsing:
128*cda5da8dSAndroid Build Coastguard Worker            self._reset_cont_handler()
129*cda5da8dSAndroid Build Coastguard Worker
130*cda5da8dSAndroid Build Coastguard Worker    def getFeature(self, name):
131*cda5da8dSAndroid Build Coastguard Worker        if name == feature_namespaces:
132*cda5da8dSAndroid Build Coastguard Worker            return self._namespaces
133*cda5da8dSAndroid Build Coastguard Worker        elif name == feature_string_interning:
134*cda5da8dSAndroid Build Coastguard Worker            return self._interning is not None
135*cda5da8dSAndroid Build Coastguard Worker        elif name in (feature_validation, feature_external_pes,
136*cda5da8dSAndroid Build Coastguard Worker                      feature_namespace_prefixes):
137*cda5da8dSAndroid Build Coastguard Worker            return 0
138*cda5da8dSAndroid Build Coastguard Worker        elif name == feature_external_ges:
139*cda5da8dSAndroid Build Coastguard Worker            return self._external_ges
140*cda5da8dSAndroid Build Coastguard Worker        raise SAXNotRecognizedException("Feature '%s' not recognized" % name)
141*cda5da8dSAndroid Build Coastguard Worker
142*cda5da8dSAndroid Build Coastguard Worker    def setFeature(self, name, state):
143*cda5da8dSAndroid Build Coastguard Worker        if self._parsing:
144*cda5da8dSAndroid Build Coastguard Worker            raise SAXNotSupportedException("Cannot set features while parsing")
145*cda5da8dSAndroid Build Coastguard Worker
146*cda5da8dSAndroid Build Coastguard Worker        if name == feature_namespaces:
147*cda5da8dSAndroid Build Coastguard Worker            self._namespaces = state
148*cda5da8dSAndroid Build Coastguard Worker        elif name == feature_external_ges:
149*cda5da8dSAndroid Build Coastguard Worker            self._external_ges = state
150*cda5da8dSAndroid Build Coastguard Worker        elif name == feature_string_interning:
151*cda5da8dSAndroid Build Coastguard Worker            if state:
152*cda5da8dSAndroid Build Coastguard Worker                if self._interning is None:
153*cda5da8dSAndroid Build Coastguard Worker                    self._interning = {}
154*cda5da8dSAndroid Build Coastguard Worker            else:
155*cda5da8dSAndroid Build Coastguard Worker                self._interning = None
156*cda5da8dSAndroid Build Coastguard Worker        elif name == feature_validation:
157*cda5da8dSAndroid Build Coastguard Worker            if state:
158*cda5da8dSAndroid Build Coastguard Worker                raise SAXNotSupportedException(
159*cda5da8dSAndroid Build Coastguard Worker                    "expat does not support validation")
160*cda5da8dSAndroid Build Coastguard Worker        elif name == feature_external_pes:
161*cda5da8dSAndroid Build Coastguard Worker            if state:
162*cda5da8dSAndroid Build Coastguard Worker                raise SAXNotSupportedException(
163*cda5da8dSAndroid Build Coastguard Worker                    "expat does not read external parameter entities")
164*cda5da8dSAndroid Build Coastguard Worker        elif name == feature_namespace_prefixes:
165*cda5da8dSAndroid Build Coastguard Worker            if state:
166*cda5da8dSAndroid Build Coastguard Worker                raise SAXNotSupportedException(
167*cda5da8dSAndroid Build Coastguard Worker                    "expat does not report namespace prefixes")
168*cda5da8dSAndroid Build Coastguard Worker        else:
169*cda5da8dSAndroid Build Coastguard Worker            raise SAXNotRecognizedException(
170*cda5da8dSAndroid Build Coastguard Worker                "Feature '%s' not recognized" % name)
171*cda5da8dSAndroid Build Coastguard Worker
172*cda5da8dSAndroid Build Coastguard Worker    def getProperty(self, name):
173*cda5da8dSAndroid Build Coastguard Worker        if name == handler.property_lexical_handler:
174*cda5da8dSAndroid Build Coastguard Worker            return self._lex_handler_prop
175*cda5da8dSAndroid Build Coastguard Worker        elif name == property_interning_dict:
176*cda5da8dSAndroid Build Coastguard Worker            return self._interning
177*cda5da8dSAndroid Build Coastguard Worker        elif name == property_xml_string:
178*cda5da8dSAndroid Build Coastguard Worker            if self._parser:
179*cda5da8dSAndroid Build Coastguard Worker                if hasattr(self._parser, "GetInputContext"):
180*cda5da8dSAndroid Build Coastguard Worker                    return self._parser.GetInputContext()
181*cda5da8dSAndroid Build Coastguard Worker                else:
182*cda5da8dSAndroid Build Coastguard Worker                    raise SAXNotRecognizedException(
183*cda5da8dSAndroid Build Coastguard Worker                        "This version of expat does not support getting"
184*cda5da8dSAndroid Build Coastguard Worker                        " the XML string")
185*cda5da8dSAndroid Build Coastguard Worker            else:
186*cda5da8dSAndroid Build Coastguard Worker                raise SAXNotSupportedException(
187*cda5da8dSAndroid Build Coastguard Worker                    "XML string cannot be returned when not parsing")
188*cda5da8dSAndroid Build Coastguard Worker        raise SAXNotRecognizedException("Property '%s' not recognized" % name)
189*cda5da8dSAndroid Build Coastguard Worker
190*cda5da8dSAndroid Build Coastguard Worker    def setProperty(self, name, value):
191*cda5da8dSAndroid Build Coastguard Worker        if name == handler.property_lexical_handler:
192*cda5da8dSAndroid Build Coastguard Worker            self._lex_handler_prop = value
193*cda5da8dSAndroid Build Coastguard Worker            if self._parsing:
194*cda5da8dSAndroid Build Coastguard Worker                self._reset_lex_handler_prop()
195*cda5da8dSAndroid Build Coastguard Worker        elif name == property_interning_dict:
196*cda5da8dSAndroid Build Coastguard Worker            self._interning = value
197*cda5da8dSAndroid Build Coastguard Worker        elif name == property_xml_string:
198*cda5da8dSAndroid Build Coastguard Worker            raise SAXNotSupportedException("Property '%s' cannot be set" %
199*cda5da8dSAndroid Build Coastguard Worker                                           name)
200*cda5da8dSAndroid Build Coastguard Worker        else:
201*cda5da8dSAndroid Build Coastguard Worker            raise SAXNotRecognizedException("Property '%s' not recognized" %
202*cda5da8dSAndroid Build Coastguard Worker                                            name)
203*cda5da8dSAndroid Build Coastguard Worker
204*cda5da8dSAndroid Build Coastguard Worker    # IncrementalParser methods
205*cda5da8dSAndroid Build Coastguard Worker
206*cda5da8dSAndroid Build Coastguard Worker    def feed(self, data, isFinal=False):
207*cda5da8dSAndroid Build Coastguard Worker        if not self._parsing:
208*cda5da8dSAndroid Build Coastguard Worker            self.reset()
209*cda5da8dSAndroid Build Coastguard Worker            self._parsing = True
210*cda5da8dSAndroid Build Coastguard Worker            self._cont_handler.startDocument()
211*cda5da8dSAndroid Build Coastguard Worker
212*cda5da8dSAndroid Build Coastguard Worker        try:
213*cda5da8dSAndroid Build Coastguard Worker            # The isFinal parameter is internal to the expat reader.
214*cda5da8dSAndroid Build Coastguard Worker            # If it is set to true, expat will check validity of the entire
215*cda5da8dSAndroid Build Coastguard Worker            # document. When feeding chunks, they are not normally final -
216*cda5da8dSAndroid Build Coastguard Worker            # except when invoked from close.
217*cda5da8dSAndroid Build Coastguard Worker            self._parser.Parse(data, isFinal)
218*cda5da8dSAndroid Build Coastguard Worker        except expat.error as e:
219*cda5da8dSAndroid Build Coastguard Worker            exc = SAXParseException(expat.ErrorString(e.code), e, self)
220*cda5da8dSAndroid Build Coastguard Worker            # FIXME: when to invoke error()?
221*cda5da8dSAndroid Build Coastguard Worker            self._err_handler.fatalError(exc)
222*cda5da8dSAndroid Build Coastguard Worker
223*cda5da8dSAndroid Build Coastguard Worker    def _close_source(self):
224*cda5da8dSAndroid Build Coastguard Worker        source = self._source
225*cda5da8dSAndroid Build Coastguard Worker        try:
226*cda5da8dSAndroid Build Coastguard Worker            file = source.getCharacterStream()
227*cda5da8dSAndroid Build Coastguard Worker            if file is not None:
228*cda5da8dSAndroid Build Coastguard Worker                file.close()
229*cda5da8dSAndroid Build Coastguard Worker        finally:
230*cda5da8dSAndroid Build Coastguard Worker            file = source.getByteStream()
231*cda5da8dSAndroid Build Coastguard Worker            if file is not None:
232*cda5da8dSAndroid Build Coastguard Worker                file.close()
233*cda5da8dSAndroid Build Coastguard Worker
234*cda5da8dSAndroid Build Coastguard Worker    def close(self):
235*cda5da8dSAndroid Build Coastguard Worker        if (self._entity_stack or self._parser is None or
236*cda5da8dSAndroid Build Coastguard Worker            isinstance(self._parser, _ClosedParser)):
237*cda5da8dSAndroid Build Coastguard Worker            # If we are completing an external entity, do nothing here
238*cda5da8dSAndroid Build Coastguard Worker            return
239*cda5da8dSAndroid Build Coastguard Worker        try:
240*cda5da8dSAndroid Build Coastguard Worker            self.feed(b"", isFinal=True)
241*cda5da8dSAndroid Build Coastguard Worker            self._cont_handler.endDocument()
242*cda5da8dSAndroid Build Coastguard Worker            self._parsing = False
243*cda5da8dSAndroid Build Coastguard Worker            # break cycle created by expat handlers pointing to our methods
244*cda5da8dSAndroid Build Coastguard Worker            self._parser = None
245*cda5da8dSAndroid Build Coastguard Worker        finally:
246*cda5da8dSAndroid Build Coastguard Worker            self._parsing = False
247*cda5da8dSAndroid Build Coastguard Worker            if self._parser is not None:
248*cda5da8dSAndroid Build Coastguard Worker                # Keep ErrorColumnNumber and ErrorLineNumber after closing.
249*cda5da8dSAndroid Build Coastguard Worker                parser = _ClosedParser()
250*cda5da8dSAndroid Build Coastguard Worker                parser.ErrorColumnNumber = self._parser.ErrorColumnNumber
251*cda5da8dSAndroid Build Coastguard Worker                parser.ErrorLineNumber = self._parser.ErrorLineNumber
252*cda5da8dSAndroid Build Coastguard Worker                self._parser = parser
253*cda5da8dSAndroid Build Coastguard Worker            self._close_source()
254*cda5da8dSAndroid Build Coastguard Worker
255*cda5da8dSAndroid Build Coastguard Worker    def _reset_cont_handler(self):
256*cda5da8dSAndroid Build Coastguard Worker        self._parser.ProcessingInstructionHandler = \
257*cda5da8dSAndroid Build Coastguard Worker                                    self._cont_handler.processingInstruction
258*cda5da8dSAndroid Build Coastguard Worker        self._parser.CharacterDataHandler = self._cont_handler.characters
259*cda5da8dSAndroid Build Coastguard Worker
260*cda5da8dSAndroid Build Coastguard Worker    def _reset_lex_handler_prop(self):
261*cda5da8dSAndroid Build Coastguard Worker        lex = self._lex_handler_prop
262*cda5da8dSAndroid Build Coastguard Worker        parser = self._parser
263*cda5da8dSAndroid Build Coastguard Worker        if lex is None:
264*cda5da8dSAndroid Build Coastguard Worker            parser.CommentHandler = None
265*cda5da8dSAndroid Build Coastguard Worker            parser.StartCdataSectionHandler = None
266*cda5da8dSAndroid Build Coastguard Worker            parser.EndCdataSectionHandler = None
267*cda5da8dSAndroid Build Coastguard Worker            parser.StartDoctypeDeclHandler = None
268*cda5da8dSAndroid Build Coastguard Worker            parser.EndDoctypeDeclHandler = None
269*cda5da8dSAndroid Build Coastguard Worker        else:
270*cda5da8dSAndroid Build Coastguard Worker            parser.CommentHandler = lex.comment
271*cda5da8dSAndroid Build Coastguard Worker            parser.StartCdataSectionHandler = lex.startCDATA
272*cda5da8dSAndroid Build Coastguard Worker            parser.EndCdataSectionHandler = lex.endCDATA
273*cda5da8dSAndroid Build Coastguard Worker            parser.StartDoctypeDeclHandler = self.start_doctype_decl
274*cda5da8dSAndroid Build Coastguard Worker            parser.EndDoctypeDeclHandler = lex.endDTD
275*cda5da8dSAndroid Build Coastguard Worker
276*cda5da8dSAndroid Build Coastguard Worker    def reset(self):
277*cda5da8dSAndroid Build Coastguard Worker        if self._namespaces:
278*cda5da8dSAndroid Build Coastguard Worker            self._parser = expat.ParserCreate(self._source.getEncoding(), " ",
279*cda5da8dSAndroid Build Coastguard Worker                                              intern=self._interning)
280*cda5da8dSAndroid Build Coastguard Worker            self._parser.namespace_prefixes = 1
281*cda5da8dSAndroid Build Coastguard Worker            self._parser.StartElementHandler = self.start_element_ns
282*cda5da8dSAndroid Build Coastguard Worker            self._parser.EndElementHandler = self.end_element_ns
283*cda5da8dSAndroid Build Coastguard Worker        else:
284*cda5da8dSAndroid Build Coastguard Worker            self._parser = expat.ParserCreate(self._source.getEncoding(),
285*cda5da8dSAndroid Build Coastguard Worker                                              intern = self._interning)
286*cda5da8dSAndroid Build Coastguard Worker            self._parser.StartElementHandler = self.start_element
287*cda5da8dSAndroid Build Coastguard Worker            self._parser.EndElementHandler = self.end_element
288*cda5da8dSAndroid Build Coastguard Worker
289*cda5da8dSAndroid Build Coastguard Worker        self._reset_cont_handler()
290*cda5da8dSAndroid Build Coastguard Worker        self._parser.UnparsedEntityDeclHandler = self.unparsed_entity_decl
291*cda5da8dSAndroid Build Coastguard Worker        self._parser.NotationDeclHandler = self.notation_decl
292*cda5da8dSAndroid Build Coastguard Worker        self._parser.StartNamespaceDeclHandler = self.start_namespace_decl
293*cda5da8dSAndroid Build Coastguard Worker        self._parser.EndNamespaceDeclHandler = self.end_namespace_decl
294*cda5da8dSAndroid Build Coastguard Worker
295*cda5da8dSAndroid Build Coastguard Worker        self._decl_handler_prop = None
296*cda5da8dSAndroid Build Coastguard Worker        if self._lex_handler_prop:
297*cda5da8dSAndroid Build Coastguard Worker            self._reset_lex_handler_prop()
298*cda5da8dSAndroid Build Coastguard Worker#         self._parser.DefaultHandler =
299*cda5da8dSAndroid Build Coastguard Worker#         self._parser.DefaultHandlerExpand =
300*cda5da8dSAndroid Build Coastguard Worker#         self._parser.NotStandaloneHandler =
301*cda5da8dSAndroid Build Coastguard Worker        self._parser.ExternalEntityRefHandler = self.external_entity_ref
302*cda5da8dSAndroid Build Coastguard Worker        try:
303*cda5da8dSAndroid Build Coastguard Worker            self._parser.SkippedEntityHandler = self.skipped_entity_handler
304*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
305*cda5da8dSAndroid Build Coastguard Worker            # This pyexpat does not support SkippedEntity
306*cda5da8dSAndroid Build Coastguard Worker            pass
307*cda5da8dSAndroid Build Coastguard Worker        self._parser.SetParamEntityParsing(
308*cda5da8dSAndroid Build Coastguard Worker            expat.XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
309*cda5da8dSAndroid Build Coastguard Worker
310*cda5da8dSAndroid Build Coastguard Worker        self._parsing = False
311*cda5da8dSAndroid Build Coastguard Worker        self._entity_stack = []
312*cda5da8dSAndroid Build Coastguard Worker
313*cda5da8dSAndroid Build Coastguard Worker    # Locator methods
314*cda5da8dSAndroid Build Coastguard Worker
315*cda5da8dSAndroid Build Coastguard Worker    def getColumnNumber(self):
316*cda5da8dSAndroid Build Coastguard Worker        if self._parser is None:
317*cda5da8dSAndroid Build Coastguard Worker            return None
318*cda5da8dSAndroid Build Coastguard Worker        return self._parser.ErrorColumnNumber
319*cda5da8dSAndroid Build Coastguard Worker
320*cda5da8dSAndroid Build Coastguard Worker    def getLineNumber(self):
321*cda5da8dSAndroid Build Coastguard Worker        if self._parser is None:
322*cda5da8dSAndroid Build Coastguard Worker            return 1
323*cda5da8dSAndroid Build Coastguard Worker        return self._parser.ErrorLineNumber
324*cda5da8dSAndroid Build Coastguard Worker
325*cda5da8dSAndroid Build Coastguard Worker    def getPublicId(self):
326*cda5da8dSAndroid Build Coastguard Worker        return self._source.getPublicId()
327*cda5da8dSAndroid Build Coastguard Worker
328*cda5da8dSAndroid Build Coastguard Worker    def getSystemId(self):
329*cda5da8dSAndroid Build Coastguard Worker        return self._source.getSystemId()
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Worker    # event handlers
332*cda5da8dSAndroid Build Coastguard Worker    def start_element(self, name, attrs):
333*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.startElement(name, AttributesImpl(attrs))
334*cda5da8dSAndroid Build Coastguard Worker
335*cda5da8dSAndroid Build Coastguard Worker    def end_element(self, name):
336*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.endElement(name)
337*cda5da8dSAndroid Build Coastguard Worker
338*cda5da8dSAndroid Build Coastguard Worker    def start_element_ns(self, name, attrs):
339*cda5da8dSAndroid Build Coastguard Worker        pair = name.split()
340*cda5da8dSAndroid Build Coastguard Worker        if len(pair) == 1:
341*cda5da8dSAndroid Build Coastguard Worker            # no namespace
342*cda5da8dSAndroid Build Coastguard Worker            pair = (None, name)
343*cda5da8dSAndroid Build Coastguard Worker        elif len(pair) == 3:
344*cda5da8dSAndroid Build Coastguard Worker            pair = pair[0], pair[1]
345*cda5da8dSAndroid Build Coastguard Worker        else:
346*cda5da8dSAndroid Build Coastguard Worker            # default namespace
347*cda5da8dSAndroid Build Coastguard Worker            pair = tuple(pair)
348*cda5da8dSAndroid Build Coastguard Worker
349*cda5da8dSAndroid Build Coastguard Worker        newattrs = {}
350*cda5da8dSAndroid Build Coastguard Worker        qnames = {}
351*cda5da8dSAndroid Build Coastguard Worker        for (aname, value) in attrs.items():
352*cda5da8dSAndroid Build Coastguard Worker            parts = aname.split()
353*cda5da8dSAndroid Build Coastguard Worker            length = len(parts)
354*cda5da8dSAndroid Build Coastguard Worker            if length == 1:
355*cda5da8dSAndroid Build Coastguard Worker                # no namespace
356*cda5da8dSAndroid Build Coastguard Worker                qname = aname
357*cda5da8dSAndroid Build Coastguard Worker                apair = (None, aname)
358*cda5da8dSAndroid Build Coastguard Worker            elif length == 3:
359*cda5da8dSAndroid Build Coastguard Worker                qname = "%s:%s" % (parts[2], parts[1])
360*cda5da8dSAndroid Build Coastguard Worker                apair = parts[0], parts[1]
361*cda5da8dSAndroid Build Coastguard Worker            else:
362*cda5da8dSAndroid Build Coastguard Worker                # default namespace
363*cda5da8dSAndroid Build Coastguard Worker                qname = parts[1]
364*cda5da8dSAndroid Build Coastguard Worker                apair = tuple(parts)
365*cda5da8dSAndroid Build Coastguard Worker
366*cda5da8dSAndroid Build Coastguard Worker            newattrs[apair] = value
367*cda5da8dSAndroid Build Coastguard Worker            qnames[apair] = qname
368*cda5da8dSAndroid Build Coastguard Worker
369*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.startElementNS(pair, None,
370*cda5da8dSAndroid Build Coastguard Worker                                          AttributesNSImpl(newattrs, qnames))
371*cda5da8dSAndroid Build Coastguard Worker
372*cda5da8dSAndroid Build Coastguard Worker    def end_element_ns(self, name):
373*cda5da8dSAndroid Build Coastguard Worker        pair = name.split()
374*cda5da8dSAndroid Build Coastguard Worker        if len(pair) == 1:
375*cda5da8dSAndroid Build Coastguard Worker            pair = (None, name)
376*cda5da8dSAndroid Build Coastguard Worker        elif len(pair) == 3:
377*cda5da8dSAndroid Build Coastguard Worker            pair = pair[0], pair[1]
378*cda5da8dSAndroid Build Coastguard Worker        else:
379*cda5da8dSAndroid Build Coastguard Worker            pair = tuple(pair)
380*cda5da8dSAndroid Build Coastguard Worker
381*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.endElementNS(pair, None)
382*cda5da8dSAndroid Build Coastguard Worker
383*cda5da8dSAndroid Build Coastguard Worker    # this is not used (call directly to ContentHandler)
384*cda5da8dSAndroid Build Coastguard Worker    def processing_instruction(self, target, data):
385*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.processingInstruction(target, data)
386*cda5da8dSAndroid Build Coastguard Worker
387*cda5da8dSAndroid Build Coastguard Worker    # this is not used (call directly to ContentHandler)
388*cda5da8dSAndroid Build Coastguard Worker    def character_data(self, data):
389*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.characters(data)
390*cda5da8dSAndroid Build Coastguard Worker
391*cda5da8dSAndroid Build Coastguard Worker    def start_namespace_decl(self, prefix, uri):
392*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.startPrefixMapping(prefix, uri)
393*cda5da8dSAndroid Build Coastguard Worker
394*cda5da8dSAndroid Build Coastguard Worker    def end_namespace_decl(self, prefix):
395*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.endPrefixMapping(prefix)
396*cda5da8dSAndroid Build Coastguard Worker
397*cda5da8dSAndroid Build Coastguard Worker    def start_doctype_decl(self, name, sysid, pubid, has_internal_subset):
398*cda5da8dSAndroid Build Coastguard Worker        self._lex_handler_prop.startDTD(name, pubid, sysid)
399*cda5da8dSAndroid Build Coastguard Worker
400*cda5da8dSAndroid Build Coastguard Worker    def unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
401*cda5da8dSAndroid Build Coastguard Worker        self._dtd_handler.unparsedEntityDecl(name, pubid, sysid, notation_name)
402*cda5da8dSAndroid Build Coastguard Worker
403*cda5da8dSAndroid Build Coastguard Worker    def notation_decl(self, name, base, sysid, pubid):
404*cda5da8dSAndroid Build Coastguard Worker        self._dtd_handler.notationDecl(name, pubid, sysid)
405*cda5da8dSAndroid Build Coastguard Worker
406*cda5da8dSAndroid Build Coastguard Worker    def external_entity_ref(self, context, base, sysid, pubid):
407*cda5da8dSAndroid Build Coastguard Worker        if not self._external_ges:
408*cda5da8dSAndroid Build Coastguard Worker            return 1
409*cda5da8dSAndroid Build Coastguard Worker
410*cda5da8dSAndroid Build Coastguard Worker        source = self._ent_handler.resolveEntity(pubid, sysid)
411*cda5da8dSAndroid Build Coastguard Worker        source = saxutils.prepare_input_source(source,
412*cda5da8dSAndroid Build Coastguard Worker                                               self._source.getSystemId() or
413*cda5da8dSAndroid Build Coastguard Worker                                               "")
414*cda5da8dSAndroid Build Coastguard Worker
415*cda5da8dSAndroid Build Coastguard Worker        self._entity_stack.append((self._parser, self._source))
416*cda5da8dSAndroid Build Coastguard Worker        self._parser = self._parser.ExternalEntityParserCreate(context)
417*cda5da8dSAndroid Build Coastguard Worker        self._source = source
418*cda5da8dSAndroid Build Coastguard Worker
419*cda5da8dSAndroid Build Coastguard Worker        try:
420*cda5da8dSAndroid Build Coastguard Worker            xmlreader.IncrementalParser.parse(self, source)
421*cda5da8dSAndroid Build Coastguard Worker        except:
422*cda5da8dSAndroid Build Coastguard Worker            return 0  # FIXME: save error info here?
423*cda5da8dSAndroid Build Coastguard Worker
424*cda5da8dSAndroid Build Coastguard Worker        (self._parser, self._source) = self._entity_stack[-1]
425*cda5da8dSAndroid Build Coastguard Worker        del self._entity_stack[-1]
426*cda5da8dSAndroid Build Coastguard Worker        return 1
427*cda5da8dSAndroid Build Coastguard Worker
428*cda5da8dSAndroid Build Coastguard Worker    def skipped_entity_handler(self, name, is_pe):
429*cda5da8dSAndroid Build Coastguard Worker        if is_pe:
430*cda5da8dSAndroid Build Coastguard Worker            # The SAX spec requires to report skipped PEs with a '%'
431*cda5da8dSAndroid Build Coastguard Worker            name = '%'+name
432*cda5da8dSAndroid Build Coastguard Worker        self._cont_handler.skippedEntity(name)
433*cda5da8dSAndroid Build Coastguard Worker
434*cda5da8dSAndroid Build Coastguard Worker# ---
435*cda5da8dSAndroid Build Coastguard Worker
436*cda5da8dSAndroid Build Coastguard Workerdef create_parser(*args, **kwargs):
437*cda5da8dSAndroid Build Coastguard Worker    return ExpatParser(*args, **kwargs)
438*cda5da8dSAndroid Build Coastguard Worker
439*cda5da8dSAndroid Build Coastguard Worker# ---
440*cda5da8dSAndroid Build Coastguard Worker
441*cda5da8dSAndroid Build Coastguard Workerif __name__ == "__main__":
442*cda5da8dSAndroid Build Coastguard Worker    import xml.sax.saxutils
443*cda5da8dSAndroid Build Coastguard Worker    p = create_parser()
444*cda5da8dSAndroid Build Coastguard Worker    p.setContentHandler(xml.sax.saxutils.XMLGenerator())
445*cda5da8dSAndroid Build Coastguard Worker    p.setErrorHandler(xml.sax.ErrorHandler())
446*cda5da8dSAndroid Build Coastguard Worker    p.parse("http://www.ibiblio.org/xml/examples/shakespeare/hamlet.xml")
447