ยปCore Development>Code coverage>Lib/xml/sax/saxutils.py

Python code coverage for Lib/xml/sax/saxutils.py

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