xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/xml/etree/ElementTree.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""Lightweight XML support for Python.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard Worker XML is an inherently hierarchical data format, and the most natural way to
4*cda5da8dSAndroid Build Coastguard Worker represent it is with a tree.  This module has two classes for this purpose:
5*cda5da8dSAndroid Build Coastguard Worker
6*cda5da8dSAndroid Build Coastguard Worker    1. ElementTree represents the whole XML document as a tree and
7*cda5da8dSAndroid Build Coastguard Worker
8*cda5da8dSAndroid Build Coastguard Worker    2. Element represents a single node in this tree.
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Worker Interactions with the whole document (reading and writing to/from files) are
11*cda5da8dSAndroid Build Coastguard Worker usually done on the ElementTree level.  Interactions with a single XML element
12*cda5da8dSAndroid Build Coastguard Worker and its sub-elements are done on the Element level.
13*cda5da8dSAndroid Build Coastguard Worker
14*cda5da8dSAndroid Build Coastguard Worker Element is a flexible container object designed to store hierarchical data
15*cda5da8dSAndroid Build Coastguard Worker structures in memory. It can be described as a cross between a list and a
16*cda5da8dSAndroid Build Coastguard Worker dictionary.  Each Element has a number of properties associated with it:
17*cda5da8dSAndroid Build Coastguard Worker
18*cda5da8dSAndroid Build Coastguard Worker    'tag' - a string containing the element's name.
19*cda5da8dSAndroid Build Coastguard Worker
20*cda5da8dSAndroid Build Coastguard Worker    'attributes' - a Python dictionary storing the element's attributes.
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Worker    'text' - a string containing the element's text content.
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Worker    'tail' - an optional string containing text after the element's end tag.
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard Worker    And a number of child elements stored in a Python sequence.
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard Worker To create an element instance, use the Element constructor,
29*cda5da8dSAndroid Build Coastguard Worker or the SubElement factory function.
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Worker You can also use the ElementTree class to wrap an element structure
32*cda5da8dSAndroid Build Coastguard Worker and convert it to and from XML.
33*cda5da8dSAndroid Build Coastguard Worker
34*cda5da8dSAndroid Build Coastguard Worker"""
35*cda5da8dSAndroid Build Coastguard Worker
36*cda5da8dSAndroid Build Coastguard Worker#---------------------------------------------------------------------
37*cda5da8dSAndroid Build Coastguard Worker# Licensed to PSF under a Contributor Agreement.
38*cda5da8dSAndroid Build Coastguard Worker# See https://www.python.org/psf/license for licensing details.
39*cda5da8dSAndroid Build Coastguard Worker#
40*cda5da8dSAndroid Build Coastguard Worker# ElementTree
41*cda5da8dSAndroid Build Coastguard Worker# Copyright (c) 1999-2008 by Fredrik Lundh.  All rights reserved.
42*cda5da8dSAndroid Build Coastguard Worker#
43*cda5da8dSAndroid Build Coastguard Worker# [email protected]
44*cda5da8dSAndroid Build Coastguard Worker# http://www.pythonware.com
45*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
46*cda5da8dSAndroid Build Coastguard Worker# The ElementTree toolkit is
47*cda5da8dSAndroid Build Coastguard Worker#
48*cda5da8dSAndroid Build Coastguard Worker# Copyright (c) 1999-2008 by Fredrik Lundh
49*cda5da8dSAndroid Build Coastguard Worker#
50*cda5da8dSAndroid Build Coastguard Worker# By obtaining, using, and/or copying this software and/or its
51*cda5da8dSAndroid Build Coastguard Worker# associated documentation, you agree that you have read, understood,
52*cda5da8dSAndroid Build Coastguard Worker# and will comply with the following terms and conditions:
53*cda5da8dSAndroid Build Coastguard Worker#
54*cda5da8dSAndroid Build Coastguard Worker# Permission to use, copy, modify, and distribute this software and
55*cda5da8dSAndroid Build Coastguard Worker# its associated documentation for any purpose and without fee is
56*cda5da8dSAndroid Build Coastguard Worker# hereby granted, provided that the above copyright notice appears in
57*cda5da8dSAndroid Build Coastguard Worker# all copies, and that both that copyright notice and this permission
58*cda5da8dSAndroid Build Coastguard Worker# notice appear in supporting documentation, and that the name of
59*cda5da8dSAndroid Build Coastguard Worker# Secret Labs AB or the author not be used in advertising or publicity
60*cda5da8dSAndroid Build Coastguard Worker# pertaining to distribution of the software without specific, written
61*cda5da8dSAndroid Build Coastguard Worker# prior permission.
62*cda5da8dSAndroid Build Coastguard Worker#
63*cda5da8dSAndroid Build Coastguard Worker# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
64*cda5da8dSAndroid Build Coastguard Worker# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
65*cda5da8dSAndroid Build Coastguard Worker# ABILITY AND FITNESS.  IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
66*cda5da8dSAndroid Build Coastguard Worker# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
67*cda5da8dSAndroid Build Coastguard Worker# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
68*cda5da8dSAndroid Build Coastguard Worker# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
69*cda5da8dSAndroid Build Coastguard Worker# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
70*cda5da8dSAndroid Build Coastguard Worker# OF THIS SOFTWARE.
71*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
72*cda5da8dSAndroid Build Coastguard Worker
73*cda5da8dSAndroid Build Coastguard Worker__all__ = [
74*cda5da8dSAndroid Build Coastguard Worker    # public symbols
75*cda5da8dSAndroid Build Coastguard Worker    "Comment",
76*cda5da8dSAndroid Build Coastguard Worker    "dump",
77*cda5da8dSAndroid Build Coastguard Worker    "Element", "ElementTree",
78*cda5da8dSAndroid Build Coastguard Worker    "fromstring", "fromstringlist",
79*cda5da8dSAndroid Build Coastguard Worker    "indent", "iselement", "iterparse",
80*cda5da8dSAndroid Build Coastguard Worker    "parse", "ParseError",
81*cda5da8dSAndroid Build Coastguard Worker    "PI", "ProcessingInstruction",
82*cda5da8dSAndroid Build Coastguard Worker    "QName",
83*cda5da8dSAndroid Build Coastguard Worker    "SubElement",
84*cda5da8dSAndroid Build Coastguard Worker    "tostring", "tostringlist",
85*cda5da8dSAndroid Build Coastguard Worker    "TreeBuilder",
86*cda5da8dSAndroid Build Coastguard Worker    "VERSION",
87*cda5da8dSAndroid Build Coastguard Worker    "XML", "XMLID",
88*cda5da8dSAndroid Build Coastguard Worker    "XMLParser", "XMLPullParser",
89*cda5da8dSAndroid Build Coastguard Worker    "register_namespace",
90*cda5da8dSAndroid Build Coastguard Worker    "canonicalize", "C14NWriterTarget",
91*cda5da8dSAndroid Build Coastguard Worker    ]
92*cda5da8dSAndroid Build Coastguard Worker
93*cda5da8dSAndroid Build Coastguard WorkerVERSION = "1.3.0"
94*cda5da8dSAndroid Build Coastguard Worker
95*cda5da8dSAndroid Build Coastguard Workerimport sys
96*cda5da8dSAndroid Build Coastguard Workerimport re
97*cda5da8dSAndroid Build Coastguard Workerimport warnings
98*cda5da8dSAndroid Build Coastguard Workerimport io
99*cda5da8dSAndroid Build Coastguard Workerimport collections
100*cda5da8dSAndroid Build Coastguard Workerimport collections.abc
101*cda5da8dSAndroid Build Coastguard Workerimport contextlib
102*cda5da8dSAndroid Build Coastguard Worker
103*cda5da8dSAndroid Build Coastguard Workerfrom . import ElementPath
104*cda5da8dSAndroid Build Coastguard Worker
105*cda5da8dSAndroid Build Coastguard Worker
106*cda5da8dSAndroid Build Coastguard Workerclass ParseError(SyntaxError):
107*cda5da8dSAndroid Build Coastguard Worker    """An error when parsing an XML document.
108*cda5da8dSAndroid Build Coastguard Worker
109*cda5da8dSAndroid Build Coastguard Worker    In addition to its exception value, a ParseError contains
110*cda5da8dSAndroid Build Coastguard Worker    two extra attributes:
111*cda5da8dSAndroid Build Coastguard Worker        'code'     - the specific exception code
112*cda5da8dSAndroid Build Coastguard Worker        'position' - the line and column of the error
113*cda5da8dSAndroid Build Coastguard Worker
114*cda5da8dSAndroid Build Coastguard Worker    """
115*cda5da8dSAndroid Build Coastguard Worker    pass
116*cda5da8dSAndroid Build Coastguard Worker
117*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
118*cda5da8dSAndroid Build Coastguard Worker
119*cda5da8dSAndroid Build Coastguard Worker
120*cda5da8dSAndroid Build Coastguard Workerdef iselement(element):
121*cda5da8dSAndroid Build Coastguard Worker    """Return True if *element* appears to be an Element."""
122*cda5da8dSAndroid Build Coastguard Worker    return hasattr(element, 'tag')
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Worker
125*cda5da8dSAndroid Build Coastguard Workerclass Element:
126*cda5da8dSAndroid Build Coastguard Worker    """An XML element.
127*cda5da8dSAndroid Build Coastguard Worker
128*cda5da8dSAndroid Build Coastguard Worker    This class is the reference implementation of the Element interface.
129*cda5da8dSAndroid Build Coastguard Worker
130*cda5da8dSAndroid Build Coastguard Worker    An element's length is its number of subelements.  That means if you
131*cda5da8dSAndroid Build Coastguard Worker    want to check if an element is truly empty, you should check BOTH
132*cda5da8dSAndroid Build Coastguard Worker    its length AND its text attribute.
133*cda5da8dSAndroid Build Coastguard Worker
134*cda5da8dSAndroid Build Coastguard Worker    The element tag, attribute names, and attribute values can be either
135*cda5da8dSAndroid Build Coastguard Worker    bytes or strings.
136*cda5da8dSAndroid Build Coastguard Worker
137*cda5da8dSAndroid Build Coastguard Worker    *tag* is the element name.  *attrib* is an optional dictionary containing
138*cda5da8dSAndroid Build Coastguard Worker    element attributes. *extra* are additional element attributes given as
139*cda5da8dSAndroid Build Coastguard Worker    keyword arguments.
140*cda5da8dSAndroid Build Coastguard Worker
141*cda5da8dSAndroid Build Coastguard Worker    Example form:
142*cda5da8dSAndroid Build Coastguard Worker        <tag attrib>text<child/>...</tag>tail
143*cda5da8dSAndroid Build Coastguard Worker
144*cda5da8dSAndroid Build Coastguard Worker    """
145*cda5da8dSAndroid Build Coastguard Worker
146*cda5da8dSAndroid Build Coastguard Worker    tag = None
147*cda5da8dSAndroid Build Coastguard Worker    """The element's name."""
148*cda5da8dSAndroid Build Coastguard Worker
149*cda5da8dSAndroid Build Coastguard Worker    attrib = None
150*cda5da8dSAndroid Build Coastguard Worker    """Dictionary of the element's attributes."""
151*cda5da8dSAndroid Build Coastguard Worker
152*cda5da8dSAndroid Build Coastguard Worker    text = None
153*cda5da8dSAndroid Build Coastguard Worker    """
154*cda5da8dSAndroid Build Coastguard Worker    Text before first subelement. This is either a string or the value None.
155*cda5da8dSAndroid Build Coastguard Worker    Note that if there is no text, this attribute may be either
156*cda5da8dSAndroid Build Coastguard Worker    None or the empty string, depending on the parser.
157*cda5da8dSAndroid Build Coastguard Worker
158*cda5da8dSAndroid Build Coastguard Worker    """
159*cda5da8dSAndroid Build Coastguard Worker
160*cda5da8dSAndroid Build Coastguard Worker    tail = None
161*cda5da8dSAndroid Build Coastguard Worker    """
162*cda5da8dSAndroid Build Coastguard Worker    Text after this element's end tag, but before the next sibling element's
163*cda5da8dSAndroid Build Coastguard Worker    start tag.  This is either a string or the value None.  Note that if there
164*cda5da8dSAndroid Build Coastguard Worker    was no text, this attribute may be either None or an empty string,
165*cda5da8dSAndroid Build Coastguard Worker    depending on the parser.
166*cda5da8dSAndroid Build Coastguard Worker
167*cda5da8dSAndroid Build Coastguard Worker    """
168*cda5da8dSAndroid Build Coastguard Worker
169*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, tag, attrib={}, **extra):
170*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(attrib, dict):
171*cda5da8dSAndroid Build Coastguard Worker            raise TypeError("attrib must be dict, not %s" % (
172*cda5da8dSAndroid Build Coastguard Worker                attrib.__class__.__name__,))
173*cda5da8dSAndroid Build Coastguard Worker        self.tag = tag
174*cda5da8dSAndroid Build Coastguard Worker        self.attrib = {**attrib, **extra}
175*cda5da8dSAndroid Build Coastguard Worker        self._children = []
176*cda5da8dSAndroid Build Coastguard Worker
177*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
178*cda5da8dSAndroid Build Coastguard Worker        return "<%s %r at %#x>" % (self.__class__.__name__, self.tag, id(self))
179*cda5da8dSAndroid Build Coastguard Worker
180*cda5da8dSAndroid Build Coastguard Worker    def makeelement(self, tag, attrib):
181*cda5da8dSAndroid Build Coastguard Worker        """Create a new element with the same type.
182*cda5da8dSAndroid Build Coastguard Worker
183*cda5da8dSAndroid Build Coastguard Worker        *tag* is a string containing the element name.
184*cda5da8dSAndroid Build Coastguard Worker        *attrib* is a dictionary containing the element attributes.
185*cda5da8dSAndroid Build Coastguard Worker
186*cda5da8dSAndroid Build Coastguard Worker        Do not call this method, use the SubElement factory function instead.
187*cda5da8dSAndroid Build Coastguard Worker
188*cda5da8dSAndroid Build Coastguard Worker        """
189*cda5da8dSAndroid Build Coastguard Worker        return self.__class__(tag, attrib)
190*cda5da8dSAndroid Build Coastguard Worker
191*cda5da8dSAndroid Build Coastguard Worker    def copy(self):
192*cda5da8dSAndroid Build Coastguard Worker        """Return copy of current element.
193*cda5da8dSAndroid Build Coastguard Worker
194*cda5da8dSAndroid Build Coastguard Worker        This creates a shallow copy. Subelements will be shared with the
195*cda5da8dSAndroid Build Coastguard Worker        original tree.
196*cda5da8dSAndroid Build Coastguard Worker
197*cda5da8dSAndroid Build Coastguard Worker        """
198*cda5da8dSAndroid Build Coastguard Worker        warnings.warn(
199*cda5da8dSAndroid Build Coastguard Worker            "elem.copy() is deprecated. Use copy.copy(elem) instead.",
200*cda5da8dSAndroid Build Coastguard Worker            DeprecationWarning
201*cda5da8dSAndroid Build Coastguard Worker            )
202*cda5da8dSAndroid Build Coastguard Worker        return self.__copy__()
203*cda5da8dSAndroid Build Coastguard Worker
204*cda5da8dSAndroid Build Coastguard Worker    def __copy__(self):
205*cda5da8dSAndroid Build Coastguard Worker        elem = self.makeelement(self.tag, self.attrib)
206*cda5da8dSAndroid Build Coastguard Worker        elem.text = self.text
207*cda5da8dSAndroid Build Coastguard Worker        elem.tail = self.tail
208*cda5da8dSAndroid Build Coastguard Worker        elem[:] = self
209*cda5da8dSAndroid Build Coastguard Worker        return elem
210*cda5da8dSAndroid Build Coastguard Worker
211*cda5da8dSAndroid Build Coastguard Worker    def __len__(self):
212*cda5da8dSAndroid Build Coastguard Worker        return len(self._children)
213*cda5da8dSAndroid Build Coastguard Worker
214*cda5da8dSAndroid Build Coastguard Worker    def __bool__(self):
215*cda5da8dSAndroid Build Coastguard Worker        warnings.warn(
216*cda5da8dSAndroid Build Coastguard Worker            "The behavior of this method will change in future versions.  "
217*cda5da8dSAndroid Build Coastguard Worker            "Use specific 'len(elem)' or 'elem is not None' test instead.",
218*cda5da8dSAndroid Build Coastguard Worker            FutureWarning, stacklevel=2
219*cda5da8dSAndroid Build Coastguard Worker            )
220*cda5da8dSAndroid Build Coastguard Worker        return len(self._children) != 0 # emulate old behaviour, for now
221*cda5da8dSAndroid Build Coastguard Worker
222*cda5da8dSAndroid Build Coastguard Worker    def __getitem__(self, index):
223*cda5da8dSAndroid Build Coastguard Worker        return self._children[index]
224*cda5da8dSAndroid Build Coastguard Worker
225*cda5da8dSAndroid Build Coastguard Worker    def __setitem__(self, index, element):
226*cda5da8dSAndroid Build Coastguard Worker        if isinstance(index, slice):
227*cda5da8dSAndroid Build Coastguard Worker            for elt in element:
228*cda5da8dSAndroid Build Coastguard Worker                self._assert_is_element(elt)
229*cda5da8dSAndroid Build Coastguard Worker        else:
230*cda5da8dSAndroid Build Coastguard Worker            self._assert_is_element(element)
231*cda5da8dSAndroid Build Coastguard Worker        self._children[index] = element
232*cda5da8dSAndroid Build Coastguard Worker
233*cda5da8dSAndroid Build Coastguard Worker    def __delitem__(self, index):
234*cda5da8dSAndroid Build Coastguard Worker        del self._children[index]
235*cda5da8dSAndroid Build Coastguard Worker
236*cda5da8dSAndroid Build Coastguard Worker    def append(self, subelement):
237*cda5da8dSAndroid Build Coastguard Worker        """Add *subelement* to the end of this element.
238*cda5da8dSAndroid Build Coastguard Worker
239*cda5da8dSAndroid Build Coastguard Worker        The new element will appear in document order after the last existing
240*cda5da8dSAndroid Build Coastguard Worker        subelement (or directly after the text, if it's the first subelement),
241*cda5da8dSAndroid Build Coastguard Worker        but before the end tag for this element.
242*cda5da8dSAndroid Build Coastguard Worker
243*cda5da8dSAndroid Build Coastguard Worker        """
244*cda5da8dSAndroid Build Coastguard Worker        self._assert_is_element(subelement)
245*cda5da8dSAndroid Build Coastguard Worker        self._children.append(subelement)
246*cda5da8dSAndroid Build Coastguard Worker
247*cda5da8dSAndroid Build Coastguard Worker    def extend(self, elements):
248*cda5da8dSAndroid Build Coastguard Worker        """Append subelements from a sequence.
249*cda5da8dSAndroid Build Coastguard Worker
250*cda5da8dSAndroid Build Coastguard Worker        *elements* is a sequence with zero or more elements.
251*cda5da8dSAndroid Build Coastguard Worker
252*cda5da8dSAndroid Build Coastguard Worker        """
253*cda5da8dSAndroid Build Coastguard Worker        for element in elements:
254*cda5da8dSAndroid Build Coastguard Worker            self._assert_is_element(element)
255*cda5da8dSAndroid Build Coastguard Worker            self._children.append(element)
256*cda5da8dSAndroid Build Coastguard Worker
257*cda5da8dSAndroid Build Coastguard Worker    def insert(self, index, subelement):
258*cda5da8dSAndroid Build Coastguard Worker        """Insert *subelement* at position *index*."""
259*cda5da8dSAndroid Build Coastguard Worker        self._assert_is_element(subelement)
260*cda5da8dSAndroid Build Coastguard Worker        self._children.insert(index, subelement)
261*cda5da8dSAndroid Build Coastguard Worker
262*cda5da8dSAndroid Build Coastguard Worker    def _assert_is_element(self, e):
263*cda5da8dSAndroid Build Coastguard Worker        # Need to refer to the actual Python implementation, not the
264*cda5da8dSAndroid Build Coastguard Worker        # shadowing C implementation.
265*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(e, _Element_Py):
266*cda5da8dSAndroid Build Coastguard Worker            raise TypeError('expected an Element, not %s' % type(e).__name__)
267*cda5da8dSAndroid Build Coastguard Worker
268*cda5da8dSAndroid Build Coastguard Worker    def remove(self, subelement):
269*cda5da8dSAndroid Build Coastguard Worker        """Remove matching subelement.
270*cda5da8dSAndroid Build Coastguard Worker
271*cda5da8dSAndroid Build Coastguard Worker        Unlike the find methods, this method compares elements based on
272*cda5da8dSAndroid Build Coastguard Worker        identity, NOT ON tag value or contents.  To remove subelements by
273*cda5da8dSAndroid Build Coastguard Worker        other means, the easiest way is to use a list comprehension to
274*cda5da8dSAndroid Build Coastguard Worker        select what elements to keep, and then use slice assignment to update
275*cda5da8dSAndroid Build Coastguard Worker        the parent element.
276*cda5da8dSAndroid Build Coastguard Worker
277*cda5da8dSAndroid Build Coastguard Worker        ValueError is raised if a matching element could not be found.
278*cda5da8dSAndroid Build Coastguard Worker
279*cda5da8dSAndroid Build Coastguard Worker        """
280*cda5da8dSAndroid Build Coastguard Worker        # assert iselement(element)
281*cda5da8dSAndroid Build Coastguard Worker        self._children.remove(subelement)
282*cda5da8dSAndroid Build Coastguard Worker
283*cda5da8dSAndroid Build Coastguard Worker    def find(self, path, namespaces=None):
284*cda5da8dSAndroid Build Coastguard Worker        """Find first matching element by tag name or path.
285*cda5da8dSAndroid Build Coastguard Worker
286*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
287*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
288*cda5da8dSAndroid Build Coastguard Worker
289*cda5da8dSAndroid Build Coastguard Worker        Return the first matching element, or None if no element was found.
290*cda5da8dSAndroid Build Coastguard Worker
291*cda5da8dSAndroid Build Coastguard Worker        """
292*cda5da8dSAndroid Build Coastguard Worker        return ElementPath.find(self, path, namespaces)
293*cda5da8dSAndroid Build Coastguard Worker
294*cda5da8dSAndroid Build Coastguard Worker    def findtext(self, path, default=None, namespaces=None):
295*cda5da8dSAndroid Build Coastguard Worker        """Find text for first matching element by tag name or path.
296*cda5da8dSAndroid Build Coastguard Worker
297*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
298*cda5da8dSAndroid Build Coastguard Worker        *default* is the value to return if the element was not found,
299*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
300*cda5da8dSAndroid Build Coastguard Worker
301*cda5da8dSAndroid Build Coastguard Worker        Return text content of first matching element, or default value if
302*cda5da8dSAndroid Build Coastguard Worker        none was found.  Note that if an element is found having no text
303*cda5da8dSAndroid Build Coastguard Worker        content, the empty string is returned.
304*cda5da8dSAndroid Build Coastguard Worker
305*cda5da8dSAndroid Build Coastguard Worker        """
306*cda5da8dSAndroid Build Coastguard Worker        return ElementPath.findtext(self, path, default, namespaces)
307*cda5da8dSAndroid Build Coastguard Worker
308*cda5da8dSAndroid Build Coastguard Worker    def findall(self, path, namespaces=None):
309*cda5da8dSAndroid Build Coastguard Worker        """Find all matching subelements by tag name or path.
310*cda5da8dSAndroid Build Coastguard Worker
311*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
312*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
313*cda5da8dSAndroid Build Coastguard Worker
314*cda5da8dSAndroid Build Coastguard Worker        Returns list containing all matching elements in document order.
315*cda5da8dSAndroid Build Coastguard Worker
316*cda5da8dSAndroid Build Coastguard Worker        """
317*cda5da8dSAndroid Build Coastguard Worker        return ElementPath.findall(self, path, namespaces)
318*cda5da8dSAndroid Build Coastguard Worker
319*cda5da8dSAndroid Build Coastguard Worker    def iterfind(self, path, namespaces=None):
320*cda5da8dSAndroid Build Coastguard Worker        """Find all matching subelements by tag name or path.
321*cda5da8dSAndroid Build Coastguard Worker
322*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
323*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
324*cda5da8dSAndroid Build Coastguard Worker
325*cda5da8dSAndroid Build Coastguard Worker        Return an iterable yielding all matching elements in document order.
326*cda5da8dSAndroid Build Coastguard Worker
327*cda5da8dSAndroid Build Coastguard Worker        """
328*cda5da8dSAndroid Build Coastguard Worker        return ElementPath.iterfind(self, path, namespaces)
329*cda5da8dSAndroid Build Coastguard Worker
330*cda5da8dSAndroid Build Coastguard Worker    def clear(self):
331*cda5da8dSAndroid Build Coastguard Worker        """Reset element.
332*cda5da8dSAndroid Build Coastguard Worker
333*cda5da8dSAndroid Build Coastguard Worker        This function removes all subelements, clears all attributes, and sets
334*cda5da8dSAndroid Build Coastguard Worker        the text and tail attributes to None.
335*cda5da8dSAndroid Build Coastguard Worker
336*cda5da8dSAndroid Build Coastguard Worker        """
337*cda5da8dSAndroid Build Coastguard Worker        self.attrib.clear()
338*cda5da8dSAndroid Build Coastguard Worker        self._children = []
339*cda5da8dSAndroid Build Coastguard Worker        self.text = self.tail = None
340*cda5da8dSAndroid Build Coastguard Worker
341*cda5da8dSAndroid Build Coastguard Worker    def get(self, key, default=None):
342*cda5da8dSAndroid Build Coastguard Worker        """Get element attribute.
343*cda5da8dSAndroid Build Coastguard Worker
344*cda5da8dSAndroid Build Coastguard Worker        Equivalent to attrib.get, but some implementations may handle this a
345*cda5da8dSAndroid Build Coastguard Worker        bit more efficiently.  *key* is what attribute to look for, and
346*cda5da8dSAndroid Build Coastguard Worker        *default* is what to return if the attribute was not found.
347*cda5da8dSAndroid Build Coastguard Worker
348*cda5da8dSAndroid Build Coastguard Worker        Returns a string containing the attribute value, or the default if
349*cda5da8dSAndroid Build Coastguard Worker        attribute was not found.
350*cda5da8dSAndroid Build Coastguard Worker
351*cda5da8dSAndroid Build Coastguard Worker        """
352*cda5da8dSAndroid Build Coastguard Worker        return self.attrib.get(key, default)
353*cda5da8dSAndroid Build Coastguard Worker
354*cda5da8dSAndroid Build Coastguard Worker    def set(self, key, value):
355*cda5da8dSAndroid Build Coastguard Worker        """Set element attribute.
356*cda5da8dSAndroid Build Coastguard Worker
357*cda5da8dSAndroid Build Coastguard Worker        Equivalent to attrib[key] = value, but some implementations may handle
358*cda5da8dSAndroid Build Coastguard Worker        this a bit more efficiently.  *key* is what attribute to set, and
359*cda5da8dSAndroid Build Coastguard Worker        *value* is the attribute value to set it to.
360*cda5da8dSAndroid Build Coastguard Worker
361*cda5da8dSAndroid Build Coastguard Worker        """
362*cda5da8dSAndroid Build Coastguard Worker        self.attrib[key] = value
363*cda5da8dSAndroid Build Coastguard Worker
364*cda5da8dSAndroid Build Coastguard Worker    def keys(self):
365*cda5da8dSAndroid Build Coastguard Worker        """Get list of attribute names.
366*cda5da8dSAndroid Build Coastguard Worker
367*cda5da8dSAndroid Build Coastguard Worker        Names are returned in an arbitrary order, just like an ordinary
368*cda5da8dSAndroid Build Coastguard Worker        Python dict.  Equivalent to attrib.keys()
369*cda5da8dSAndroid Build Coastguard Worker
370*cda5da8dSAndroid Build Coastguard Worker        """
371*cda5da8dSAndroid Build Coastguard Worker        return self.attrib.keys()
372*cda5da8dSAndroid Build Coastguard Worker
373*cda5da8dSAndroid Build Coastguard Worker    def items(self):
374*cda5da8dSAndroid Build Coastguard Worker        """Get element attributes as a sequence.
375*cda5da8dSAndroid Build Coastguard Worker
376*cda5da8dSAndroid Build Coastguard Worker        The attributes are returned in arbitrary order.  Equivalent to
377*cda5da8dSAndroid Build Coastguard Worker        attrib.items().
378*cda5da8dSAndroid Build Coastguard Worker
379*cda5da8dSAndroid Build Coastguard Worker        Return a list of (name, value) tuples.
380*cda5da8dSAndroid Build Coastguard Worker
381*cda5da8dSAndroid Build Coastguard Worker        """
382*cda5da8dSAndroid Build Coastguard Worker        return self.attrib.items()
383*cda5da8dSAndroid Build Coastguard Worker
384*cda5da8dSAndroid Build Coastguard Worker    def iter(self, tag=None):
385*cda5da8dSAndroid Build Coastguard Worker        """Create tree iterator.
386*cda5da8dSAndroid Build Coastguard Worker
387*cda5da8dSAndroid Build Coastguard Worker        The iterator loops over the element and all subelements in document
388*cda5da8dSAndroid Build Coastguard Worker        order, returning all elements with a matching tag.
389*cda5da8dSAndroid Build Coastguard Worker
390*cda5da8dSAndroid Build Coastguard Worker        If the tree structure is modified during iteration, new or removed
391*cda5da8dSAndroid Build Coastguard Worker        elements may or may not be included.  To get a stable set, use the
392*cda5da8dSAndroid Build Coastguard Worker        list() function on the iterator, and loop over the resulting list.
393*cda5da8dSAndroid Build Coastguard Worker
394*cda5da8dSAndroid Build Coastguard Worker        *tag* is what tags to look for (default is to return all elements)
395*cda5da8dSAndroid Build Coastguard Worker
396*cda5da8dSAndroid Build Coastguard Worker        Return an iterator containing all the matching elements.
397*cda5da8dSAndroid Build Coastguard Worker
398*cda5da8dSAndroid Build Coastguard Worker        """
399*cda5da8dSAndroid Build Coastguard Worker        if tag == "*":
400*cda5da8dSAndroid Build Coastguard Worker            tag = None
401*cda5da8dSAndroid Build Coastguard Worker        if tag is None or self.tag == tag:
402*cda5da8dSAndroid Build Coastguard Worker            yield self
403*cda5da8dSAndroid Build Coastguard Worker        for e in self._children:
404*cda5da8dSAndroid Build Coastguard Worker            yield from e.iter(tag)
405*cda5da8dSAndroid Build Coastguard Worker
406*cda5da8dSAndroid Build Coastguard Worker    def itertext(self):
407*cda5da8dSAndroid Build Coastguard Worker        """Create text iterator.
408*cda5da8dSAndroid Build Coastguard Worker
409*cda5da8dSAndroid Build Coastguard Worker        The iterator loops over the element and all subelements in document
410*cda5da8dSAndroid Build Coastguard Worker        order, returning all inner text.
411*cda5da8dSAndroid Build Coastguard Worker
412*cda5da8dSAndroid Build Coastguard Worker        """
413*cda5da8dSAndroid Build Coastguard Worker        tag = self.tag
414*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(tag, str) and tag is not None:
415*cda5da8dSAndroid Build Coastguard Worker            return
416*cda5da8dSAndroid Build Coastguard Worker        t = self.text
417*cda5da8dSAndroid Build Coastguard Worker        if t:
418*cda5da8dSAndroid Build Coastguard Worker            yield t
419*cda5da8dSAndroid Build Coastguard Worker        for e in self:
420*cda5da8dSAndroid Build Coastguard Worker            yield from e.itertext()
421*cda5da8dSAndroid Build Coastguard Worker            t = e.tail
422*cda5da8dSAndroid Build Coastguard Worker            if t:
423*cda5da8dSAndroid Build Coastguard Worker                yield t
424*cda5da8dSAndroid Build Coastguard Worker
425*cda5da8dSAndroid Build Coastguard Worker
426*cda5da8dSAndroid Build Coastguard Workerdef SubElement(parent, tag, attrib={}, **extra):
427*cda5da8dSAndroid Build Coastguard Worker    """Subelement factory which creates an element instance, and appends it
428*cda5da8dSAndroid Build Coastguard Worker    to an existing parent.
429*cda5da8dSAndroid Build Coastguard Worker
430*cda5da8dSAndroid Build Coastguard Worker    The element tag, attribute names, and attribute values can be either
431*cda5da8dSAndroid Build Coastguard Worker    bytes or Unicode strings.
432*cda5da8dSAndroid Build Coastguard Worker
433*cda5da8dSAndroid Build Coastguard Worker    *parent* is the parent element, *tag* is the subelements name, *attrib* is
434*cda5da8dSAndroid Build Coastguard Worker    an optional directory containing element attributes, *extra* are
435*cda5da8dSAndroid Build Coastguard Worker    additional attributes given as keyword arguments.
436*cda5da8dSAndroid Build Coastguard Worker
437*cda5da8dSAndroid Build Coastguard Worker    """
438*cda5da8dSAndroid Build Coastguard Worker    attrib = {**attrib, **extra}
439*cda5da8dSAndroid Build Coastguard Worker    element = parent.makeelement(tag, attrib)
440*cda5da8dSAndroid Build Coastguard Worker    parent.append(element)
441*cda5da8dSAndroid Build Coastguard Worker    return element
442*cda5da8dSAndroid Build Coastguard Worker
443*cda5da8dSAndroid Build Coastguard Worker
444*cda5da8dSAndroid Build Coastguard Workerdef Comment(text=None):
445*cda5da8dSAndroid Build Coastguard Worker    """Comment element factory.
446*cda5da8dSAndroid Build Coastguard Worker
447*cda5da8dSAndroid Build Coastguard Worker    This function creates a special element which the standard serializer
448*cda5da8dSAndroid Build Coastguard Worker    serializes as an XML comment.
449*cda5da8dSAndroid Build Coastguard Worker
450*cda5da8dSAndroid Build Coastguard Worker    *text* is a string containing the comment string.
451*cda5da8dSAndroid Build Coastguard Worker
452*cda5da8dSAndroid Build Coastguard Worker    """
453*cda5da8dSAndroid Build Coastguard Worker    element = Element(Comment)
454*cda5da8dSAndroid Build Coastguard Worker    element.text = text
455*cda5da8dSAndroid Build Coastguard Worker    return element
456*cda5da8dSAndroid Build Coastguard Worker
457*cda5da8dSAndroid Build Coastguard Worker
458*cda5da8dSAndroid Build Coastguard Workerdef ProcessingInstruction(target, text=None):
459*cda5da8dSAndroid Build Coastguard Worker    """Processing Instruction element factory.
460*cda5da8dSAndroid Build Coastguard Worker
461*cda5da8dSAndroid Build Coastguard Worker    This function creates a special element which the standard serializer
462*cda5da8dSAndroid Build Coastguard Worker    serializes as an XML comment.
463*cda5da8dSAndroid Build Coastguard Worker
464*cda5da8dSAndroid Build Coastguard Worker    *target* is a string containing the processing instruction, *text* is a
465*cda5da8dSAndroid Build Coastguard Worker    string containing the processing instruction contents, if any.
466*cda5da8dSAndroid Build Coastguard Worker
467*cda5da8dSAndroid Build Coastguard Worker    """
468*cda5da8dSAndroid Build Coastguard Worker    element = Element(ProcessingInstruction)
469*cda5da8dSAndroid Build Coastguard Worker    element.text = target
470*cda5da8dSAndroid Build Coastguard Worker    if text:
471*cda5da8dSAndroid Build Coastguard Worker        element.text = element.text + " " + text
472*cda5da8dSAndroid Build Coastguard Worker    return element
473*cda5da8dSAndroid Build Coastguard Worker
474*cda5da8dSAndroid Build Coastguard WorkerPI = ProcessingInstruction
475*cda5da8dSAndroid Build Coastguard Worker
476*cda5da8dSAndroid Build Coastguard Worker
477*cda5da8dSAndroid Build Coastguard Workerclass QName:
478*cda5da8dSAndroid Build Coastguard Worker    """Qualified name wrapper.
479*cda5da8dSAndroid Build Coastguard Worker
480*cda5da8dSAndroid Build Coastguard Worker    This class can be used to wrap a QName attribute value in order to get
481*cda5da8dSAndroid Build Coastguard Worker    proper namespace handing on output.
482*cda5da8dSAndroid Build Coastguard Worker
483*cda5da8dSAndroid Build Coastguard Worker    *text_or_uri* is a string containing the QName value either in the form
484*cda5da8dSAndroid Build Coastguard Worker    {uri}local, or if the tag argument is given, the URI part of a QName.
485*cda5da8dSAndroid Build Coastguard Worker
486*cda5da8dSAndroid Build Coastguard Worker    *tag* is an optional argument which if given, will make the first
487*cda5da8dSAndroid Build Coastguard Worker    argument (text_or_uri) be interpreted as a URI, and this argument (tag)
488*cda5da8dSAndroid Build Coastguard Worker    be interpreted as a local name.
489*cda5da8dSAndroid Build Coastguard Worker
490*cda5da8dSAndroid Build Coastguard Worker    """
491*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, text_or_uri, tag=None):
492*cda5da8dSAndroid Build Coastguard Worker        if tag:
493*cda5da8dSAndroid Build Coastguard Worker            text_or_uri = "{%s}%s" % (text_or_uri, tag)
494*cda5da8dSAndroid Build Coastguard Worker        self.text = text_or_uri
495*cda5da8dSAndroid Build Coastguard Worker    def __str__(self):
496*cda5da8dSAndroid Build Coastguard Worker        return self.text
497*cda5da8dSAndroid Build Coastguard Worker    def __repr__(self):
498*cda5da8dSAndroid Build Coastguard Worker        return '<%s %r>' % (self.__class__.__name__, self.text)
499*cda5da8dSAndroid Build Coastguard Worker    def __hash__(self):
500*cda5da8dSAndroid Build Coastguard Worker        return hash(self.text)
501*cda5da8dSAndroid Build Coastguard Worker    def __le__(self, other):
502*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, QName):
503*cda5da8dSAndroid Build Coastguard Worker            return self.text <= other.text
504*cda5da8dSAndroid Build Coastguard Worker        return self.text <= other
505*cda5da8dSAndroid Build Coastguard Worker    def __lt__(self, other):
506*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, QName):
507*cda5da8dSAndroid Build Coastguard Worker            return self.text < other.text
508*cda5da8dSAndroid Build Coastguard Worker        return self.text < other
509*cda5da8dSAndroid Build Coastguard Worker    def __ge__(self, other):
510*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, QName):
511*cda5da8dSAndroid Build Coastguard Worker            return self.text >= other.text
512*cda5da8dSAndroid Build Coastguard Worker        return self.text >= other
513*cda5da8dSAndroid Build Coastguard Worker    def __gt__(self, other):
514*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, QName):
515*cda5da8dSAndroid Build Coastguard Worker            return self.text > other.text
516*cda5da8dSAndroid Build Coastguard Worker        return self.text > other
517*cda5da8dSAndroid Build Coastguard Worker    def __eq__(self, other):
518*cda5da8dSAndroid Build Coastguard Worker        if isinstance(other, QName):
519*cda5da8dSAndroid Build Coastguard Worker            return self.text == other.text
520*cda5da8dSAndroid Build Coastguard Worker        return self.text == other
521*cda5da8dSAndroid Build Coastguard Worker
522*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
523*cda5da8dSAndroid Build Coastguard Worker
524*cda5da8dSAndroid Build Coastguard Worker
525*cda5da8dSAndroid Build Coastguard Workerclass ElementTree:
526*cda5da8dSAndroid Build Coastguard Worker    """An XML element hierarchy.
527*cda5da8dSAndroid Build Coastguard Worker
528*cda5da8dSAndroid Build Coastguard Worker    This class also provides support for serialization to and from
529*cda5da8dSAndroid Build Coastguard Worker    standard XML.
530*cda5da8dSAndroid Build Coastguard Worker
531*cda5da8dSAndroid Build Coastguard Worker    *element* is an optional root element node,
532*cda5da8dSAndroid Build Coastguard Worker    *file* is an optional file handle or file name of an XML file whose
533*cda5da8dSAndroid Build Coastguard Worker    contents will be used to initialize the tree with.
534*cda5da8dSAndroid Build Coastguard Worker
535*cda5da8dSAndroid Build Coastguard Worker    """
536*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, element=None, file=None):
537*cda5da8dSAndroid Build Coastguard Worker        # assert element is None or iselement(element)
538*cda5da8dSAndroid Build Coastguard Worker        self._root = element # first node
539*cda5da8dSAndroid Build Coastguard Worker        if file:
540*cda5da8dSAndroid Build Coastguard Worker            self.parse(file)
541*cda5da8dSAndroid Build Coastguard Worker
542*cda5da8dSAndroid Build Coastguard Worker    def getroot(self):
543*cda5da8dSAndroid Build Coastguard Worker        """Return root element of this tree."""
544*cda5da8dSAndroid Build Coastguard Worker        return self._root
545*cda5da8dSAndroid Build Coastguard Worker
546*cda5da8dSAndroid Build Coastguard Worker    def _setroot(self, element):
547*cda5da8dSAndroid Build Coastguard Worker        """Replace root element of this tree.
548*cda5da8dSAndroid Build Coastguard Worker
549*cda5da8dSAndroid Build Coastguard Worker        This will discard the current contents of the tree and replace it
550*cda5da8dSAndroid Build Coastguard Worker        with the given element.  Use with care!
551*cda5da8dSAndroid Build Coastguard Worker
552*cda5da8dSAndroid Build Coastguard Worker        """
553*cda5da8dSAndroid Build Coastguard Worker        # assert iselement(element)
554*cda5da8dSAndroid Build Coastguard Worker        self._root = element
555*cda5da8dSAndroid Build Coastguard Worker
556*cda5da8dSAndroid Build Coastguard Worker    def parse(self, source, parser=None):
557*cda5da8dSAndroid Build Coastguard Worker        """Load external XML document into element tree.
558*cda5da8dSAndroid Build Coastguard Worker
559*cda5da8dSAndroid Build Coastguard Worker        *source* is a file name or file object, *parser* is an optional parser
560*cda5da8dSAndroid Build Coastguard Worker        instance that defaults to XMLParser.
561*cda5da8dSAndroid Build Coastguard Worker
562*cda5da8dSAndroid Build Coastguard Worker        ParseError is raised if the parser fails to parse the document.
563*cda5da8dSAndroid Build Coastguard Worker
564*cda5da8dSAndroid Build Coastguard Worker        Returns the root element of the given source document.
565*cda5da8dSAndroid Build Coastguard Worker
566*cda5da8dSAndroid Build Coastguard Worker        """
567*cda5da8dSAndroid Build Coastguard Worker        close_source = False
568*cda5da8dSAndroid Build Coastguard Worker        if not hasattr(source, "read"):
569*cda5da8dSAndroid Build Coastguard Worker            source = open(source, "rb")
570*cda5da8dSAndroid Build Coastguard Worker            close_source = True
571*cda5da8dSAndroid Build Coastguard Worker        try:
572*cda5da8dSAndroid Build Coastguard Worker            if parser is None:
573*cda5da8dSAndroid Build Coastguard Worker                # If no parser was specified, create a default XMLParser
574*cda5da8dSAndroid Build Coastguard Worker                parser = XMLParser()
575*cda5da8dSAndroid Build Coastguard Worker                if hasattr(parser, '_parse_whole'):
576*cda5da8dSAndroid Build Coastguard Worker                    # The default XMLParser, when it comes from an accelerator,
577*cda5da8dSAndroid Build Coastguard Worker                    # can define an internal _parse_whole API for efficiency.
578*cda5da8dSAndroid Build Coastguard Worker                    # It can be used to parse the whole source without feeding
579*cda5da8dSAndroid Build Coastguard Worker                    # it with chunks.
580*cda5da8dSAndroid Build Coastguard Worker                    self._root = parser._parse_whole(source)
581*cda5da8dSAndroid Build Coastguard Worker                    return self._root
582*cda5da8dSAndroid Build Coastguard Worker            while True:
583*cda5da8dSAndroid Build Coastguard Worker                data = source.read(65536)
584*cda5da8dSAndroid Build Coastguard Worker                if not data:
585*cda5da8dSAndroid Build Coastguard Worker                    break
586*cda5da8dSAndroid Build Coastguard Worker                parser.feed(data)
587*cda5da8dSAndroid Build Coastguard Worker            self._root = parser.close()
588*cda5da8dSAndroid Build Coastguard Worker            return self._root
589*cda5da8dSAndroid Build Coastguard Worker        finally:
590*cda5da8dSAndroid Build Coastguard Worker            if close_source:
591*cda5da8dSAndroid Build Coastguard Worker                source.close()
592*cda5da8dSAndroid Build Coastguard Worker
593*cda5da8dSAndroid Build Coastguard Worker    def iter(self, tag=None):
594*cda5da8dSAndroid Build Coastguard Worker        """Create and return tree iterator for the root element.
595*cda5da8dSAndroid Build Coastguard Worker
596*cda5da8dSAndroid Build Coastguard Worker        The iterator loops over all elements in this tree, in document order.
597*cda5da8dSAndroid Build Coastguard Worker
598*cda5da8dSAndroid Build Coastguard Worker        *tag* is a string with the tag name to iterate over
599*cda5da8dSAndroid Build Coastguard Worker        (default is to return all elements).
600*cda5da8dSAndroid Build Coastguard Worker
601*cda5da8dSAndroid Build Coastguard Worker        """
602*cda5da8dSAndroid Build Coastguard Worker        # assert self._root is not None
603*cda5da8dSAndroid Build Coastguard Worker        return self._root.iter(tag)
604*cda5da8dSAndroid Build Coastguard Worker
605*cda5da8dSAndroid Build Coastguard Worker    def find(self, path, namespaces=None):
606*cda5da8dSAndroid Build Coastguard Worker        """Find first matching element by tag name or path.
607*cda5da8dSAndroid Build Coastguard Worker
608*cda5da8dSAndroid Build Coastguard Worker        Same as getroot().find(path), which is Element.find()
609*cda5da8dSAndroid Build Coastguard Worker
610*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
611*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
612*cda5da8dSAndroid Build Coastguard Worker
613*cda5da8dSAndroid Build Coastguard Worker        Return the first matching element, or None if no element was found.
614*cda5da8dSAndroid Build Coastguard Worker
615*cda5da8dSAndroid Build Coastguard Worker        """
616*cda5da8dSAndroid Build Coastguard Worker        # assert self._root is not None
617*cda5da8dSAndroid Build Coastguard Worker        if path[:1] == "/":
618*cda5da8dSAndroid Build Coastguard Worker            path = "." + path
619*cda5da8dSAndroid Build Coastguard Worker            warnings.warn(
620*cda5da8dSAndroid Build Coastguard Worker                "This search is broken in 1.3 and earlier, and will be "
621*cda5da8dSAndroid Build Coastguard Worker                "fixed in a future version.  If you rely on the current "
622*cda5da8dSAndroid Build Coastguard Worker                "behaviour, change it to %r" % path,
623*cda5da8dSAndroid Build Coastguard Worker                FutureWarning, stacklevel=2
624*cda5da8dSAndroid Build Coastguard Worker                )
625*cda5da8dSAndroid Build Coastguard Worker        return self._root.find(path, namespaces)
626*cda5da8dSAndroid Build Coastguard Worker
627*cda5da8dSAndroid Build Coastguard Worker    def findtext(self, path, default=None, namespaces=None):
628*cda5da8dSAndroid Build Coastguard Worker        """Find first matching element by tag name or path.
629*cda5da8dSAndroid Build Coastguard Worker
630*cda5da8dSAndroid Build Coastguard Worker        Same as getroot().findtext(path),  which is Element.findtext()
631*cda5da8dSAndroid Build Coastguard Worker
632*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
633*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
634*cda5da8dSAndroid Build Coastguard Worker
635*cda5da8dSAndroid Build Coastguard Worker        Return the first matching element, or None if no element was found.
636*cda5da8dSAndroid Build Coastguard Worker
637*cda5da8dSAndroid Build Coastguard Worker        """
638*cda5da8dSAndroid Build Coastguard Worker        # assert self._root is not None
639*cda5da8dSAndroid Build Coastguard Worker        if path[:1] == "/":
640*cda5da8dSAndroid Build Coastguard Worker            path = "." + path
641*cda5da8dSAndroid Build Coastguard Worker            warnings.warn(
642*cda5da8dSAndroid Build Coastguard Worker                "This search is broken in 1.3 and earlier, and will be "
643*cda5da8dSAndroid Build Coastguard Worker                "fixed in a future version.  If you rely on the current "
644*cda5da8dSAndroid Build Coastguard Worker                "behaviour, change it to %r" % path,
645*cda5da8dSAndroid Build Coastguard Worker                FutureWarning, stacklevel=2
646*cda5da8dSAndroid Build Coastguard Worker                )
647*cda5da8dSAndroid Build Coastguard Worker        return self._root.findtext(path, default, namespaces)
648*cda5da8dSAndroid Build Coastguard Worker
649*cda5da8dSAndroid Build Coastguard Worker    def findall(self, path, namespaces=None):
650*cda5da8dSAndroid Build Coastguard Worker        """Find all matching subelements by tag name or path.
651*cda5da8dSAndroid Build Coastguard Worker
652*cda5da8dSAndroid Build Coastguard Worker        Same as getroot().findall(path), which is Element.findall().
653*cda5da8dSAndroid Build Coastguard Worker
654*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
655*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
656*cda5da8dSAndroid Build Coastguard Worker
657*cda5da8dSAndroid Build Coastguard Worker        Return list containing all matching elements in document order.
658*cda5da8dSAndroid Build Coastguard Worker
659*cda5da8dSAndroid Build Coastguard Worker        """
660*cda5da8dSAndroid Build Coastguard Worker        # assert self._root is not None
661*cda5da8dSAndroid Build Coastguard Worker        if path[:1] == "/":
662*cda5da8dSAndroid Build Coastguard Worker            path = "." + path
663*cda5da8dSAndroid Build Coastguard Worker            warnings.warn(
664*cda5da8dSAndroid Build Coastguard Worker                "This search is broken in 1.3 and earlier, and will be "
665*cda5da8dSAndroid Build Coastguard Worker                "fixed in a future version.  If you rely on the current "
666*cda5da8dSAndroid Build Coastguard Worker                "behaviour, change it to %r" % path,
667*cda5da8dSAndroid Build Coastguard Worker                FutureWarning, stacklevel=2
668*cda5da8dSAndroid Build Coastguard Worker                )
669*cda5da8dSAndroid Build Coastguard Worker        return self._root.findall(path, namespaces)
670*cda5da8dSAndroid Build Coastguard Worker
671*cda5da8dSAndroid Build Coastguard Worker    def iterfind(self, path, namespaces=None):
672*cda5da8dSAndroid Build Coastguard Worker        """Find all matching subelements by tag name or path.
673*cda5da8dSAndroid Build Coastguard Worker
674*cda5da8dSAndroid Build Coastguard Worker        Same as getroot().iterfind(path), which is element.iterfind()
675*cda5da8dSAndroid Build Coastguard Worker
676*cda5da8dSAndroid Build Coastguard Worker        *path* is a string having either an element tag or an XPath,
677*cda5da8dSAndroid Build Coastguard Worker        *namespaces* is an optional mapping from namespace prefix to full name.
678*cda5da8dSAndroid Build Coastguard Worker
679*cda5da8dSAndroid Build Coastguard Worker        Return an iterable yielding all matching elements in document order.
680*cda5da8dSAndroid Build Coastguard Worker
681*cda5da8dSAndroid Build Coastguard Worker        """
682*cda5da8dSAndroid Build Coastguard Worker        # assert self._root is not None
683*cda5da8dSAndroid Build Coastguard Worker        if path[:1] == "/":
684*cda5da8dSAndroid Build Coastguard Worker            path = "." + path
685*cda5da8dSAndroid Build Coastguard Worker            warnings.warn(
686*cda5da8dSAndroid Build Coastguard Worker                "This search is broken in 1.3 and earlier, and will be "
687*cda5da8dSAndroid Build Coastguard Worker                "fixed in a future version.  If you rely on the current "
688*cda5da8dSAndroid Build Coastguard Worker                "behaviour, change it to %r" % path,
689*cda5da8dSAndroid Build Coastguard Worker                FutureWarning, stacklevel=2
690*cda5da8dSAndroid Build Coastguard Worker                )
691*cda5da8dSAndroid Build Coastguard Worker        return self._root.iterfind(path, namespaces)
692*cda5da8dSAndroid Build Coastguard Worker
693*cda5da8dSAndroid Build Coastguard Worker    def write(self, file_or_filename,
694*cda5da8dSAndroid Build Coastguard Worker              encoding=None,
695*cda5da8dSAndroid Build Coastguard Worker              xml_declaration=None,
696*cda5da8dSAndroid Build Coastguard Worker              default_namespace=None,
697*cda5da8dSAndroid Build Coastguard Worker              method=None, *,
698*cda5da8dSAndroid Build Coastguard Worker              short_empty_elements=True):
699*cda5da8dSAndroid Build Coastguard Worker        """Write element tree to a file as XML.
700*cda5da8dSAndroid Build Coastguard Worker
701*cda5da8dSAndroid Build Coastguard Worker        Arguments:
702*cda5da8dSAndroid Build Coastguard Worker          *file_or_filename* -- file name or a file object opened for writing
703*cda5da8dSAndroid Build Coastguard Worker
704*cda5da8dSAndroid Build Coastguard Worker          *encoding* -- the output encoding (default: US-ASCII)
705*cda5da8dSAndroid Build Coastguard Worker
706*cda5da8dSAndroid Build Coastguard Worker          *xml_declaration* -- bool indicating if an XML declaration should be
707*cda5da8dSAndroid Build Coastguard Worker                               added to the output. If None, an XML declaration
708*cda5da8dSAndroid Build Coastguard Worker                               is added if encoding IS NOT either of:
709*cda5da8dSAndroid Build Coastguard Worker                               US-ASCII, UTF-8, or Unicode
710*cda5da8dSAndroid Build Coastguard Worker
711*cda5da8dSAndroid Build Coastguard Worker          *default_namespace* -- sets the default XML namespace (for "xmlns")
712*cda5da8dSAndroid Build Coastguard Worker
713*cda5da8dSAndroid Build Coastguard Worker          *method* -- either "xml" (default), "html, "text", or "c14n"
714*cda5da8dSAndroid Build Coastguard Worker
715*cda5da8dSAndroid Build Coastguard Worker          *short_empty_elements* -- controls the formatting of elements
716*cda5da8dSAndroid Build Coastguard Worker                                    that contain no content. If True (default)
717*cda5da8dSAndroid Build Coastguard Worker                                    they are emitted as a single self-closed
718*cda5da8dSAndroid Build Coastguard Worker                                    tag, otherwise they are emitted as a pair
719*cda5da8dSAndroid Build Coastguard Worker                                    of start/end tags
720*cda5da8dSAndroid Build Coastguard Worker
721*cda5da8dSAndroid Build Coastguard Worker        """
722*cda5da8dSAndroid Build Coastguard Worker        if not method:
723*cda5da8dSAndroid Build Coastguard Worker            method = "xml"
724*cda5da8dSAndroid Build Coastguard Worker        elif method not in _serialize:
725*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("unknown method %r" % method)
726*cda5da8dSAndroid Build Coastguard Worker        if not encoding:
727*cda5da8dSAndroid Build Coastguard Worker            if method == "c14n":
728*cda5da8dSAndroid Build Coastguard Worker                encoding = "utf-8"
729*cda5da8dSAndroid Build Coastguard Worker            else:
730*cda5da8dSAndroid Build Coastguard Worker                encoding = "us-ascii"
731*cda5da8dSAndroid Build Coastguard Worker        with _get_writer(file_or_filename, encoding) as (write, declared_encoding):
732*cda5da8dSAndroid Build Coastguard Worker            if method == "xml" and (xml_declaration or
733*cda5da8dSAndroid Build Coastguard Worker                    (xml_declaration is None and
734*cda5da8dSAndroid Build Coastguard Worker                     encoding.lower() != "unicode" and
735*cda5da8dSAndroid Build Coastguard Worker                     declared_encoding.lower() not in ("utf-8", "us-ascii"))):
736*cda5da8dSAndroid Build Coastguard Worker                write("<?xml version='1.0' encoding='%s'?>\n" % (
737*cda5da8dSAndroid Build Coastguard Worker                    declared_encoding,))
738*cda5da8dSAndroid Build Coastguard Worker            if method == "text":
739*cda5da8dSAndroid Build Coastguard Worker                _serialize_text(write, self._root)
740*cda5da8dSAndroid Build Coastguard Worker            else:
741*cda5da8dSAndroid Build Coastguard Worker                qnames, namespaces = _namespaces(self._root, default_namespace)
742*cda5da8dSAndroid Build Coastguard Worker                serialize = _serialize[method]
743*cda5da8dSAndroid Build Coastguard Worker                serialize(write, self._root, qnames, namespaces,
744*cda5da8dSAndroid Build Coastguard Worker                          short_empty_elements=short_empty_elements)
745*cda5da8dSAndroid Build Coastguard Worker
746*cda5da8dSAndroid Build Coastguard Worker    def write_c14n(self, file):
747*cda5da8dSAndroid Build Coastguard Worker        # lxml.etree compatibility.  use output method instead
748*cda5da8dSAndroid Build Coastguard Worker        return self.write(file, method="c14n")
749*cda5da8dSAndroid Build Coastguard Worker
750*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
751*cda5da8dSAndroid Build Coastguard Worker# serialization support
752*cda5da8dSAndroid Build Coastguard Worker
753*cda5da8dSAndroid Build Coastguard Worker@contextlib.contextmanager
754*cda5da8dSAndroid Build Coastguard Workerdef _get_writer(file_or_filename, encoding):
755*cda5da8dSAndroid Build Coastguard Worker    # returns text write method and release all resources after using
756*cda5da8dSAndroid Build Coastguard Worker    try:
757*cda5da8dSAndroid Build Coastguard Worker        write = file_or_filename.write
758*cda5da8dSAndroid Build Coastguard Worker    except AttributeError:
759*cda5da8dSAndroid Build Coastguard Worker        # file_or_filename is a file name
760*cda5da8dSAndroid Build Coastguard Worker        if encoding.lower() == "unicode":
761*cda5da8dSAndroid Build Coastguard Worker            encoding="utf-8"
762*cda5da8dSAndroid Build Coastguard Worker        with open(file_or_filename, "w", encoding=encoding,
763*cda5da8dSAndroid Build Coastguard Worker                  errors="xmlcharrefreplace") as file:
764*cda5da8dSAndroid Build Coastguard Worker            yield file.write, encoding
765*cda5da8dSAndroid Build Coastguard Worker    else:
766*cda5da8dSAndroid Build Coastguard Worker        # file_or_filename is a file-like object
767*cda5da8dSAndroid Build Coastguard Worker        # encoding determines if it is a text or binary writer
768*cda5da8dSAndroid Build Coastguard Worker        if encoding.lower() == "unicode":
769*cda5da8dSAndroid Build Coastguard Worker            # use a text writer as is
770*cda5da8dSAndroid Build Coastguard Worker            yield write, getattr(file_or_filename, "encoding", None) or "utf-8"
771*cda5da8dSAndroid Build Coastguard Worker        else:
772*cda5da8dSAndroid Build Coastguard Worker            # wrap a binary writer with TextIOWrapper
773*cda5da8dSAndroid Build Coastguard Worker            with contextlib.ExitStack() as stack:
774*cda5da8dSAndroid Build Coastguard Worker                if isinstance(file_or_filename, io.BufferedIOBase):
775*cda5da8dSAndroid Build Coastguard Worker                    file = file_or_filename
776*cda5da8dSAndroid Build Coastguard Worker                elif isinstance(file_or_filename, io.RawIOBase):
777*cda5da8dSAndroid Build Coastguard Worker                    file = io.BufferedWriter(file_or_filename)
778*cda5da8dSAndroid Build Coastguard Worker                    # Keep the original file open when the BufferedWriter is
779*cda5da8dSAndroid Build Coastguard Worker                    # destroyed
780*cda5da8dSAndroid Build Coastguard Worker                    stack.callback(file.detach)
781*cda5da8dSAndroid Build Coastguard Worker                else:
782*cda5da8dSAndroid Build Coastguard Worker                    # This is to handle passed objects that aren't in the
783*cda5da8dSAndroid Build Coastguard Worker                    # IOBase hierarchy, but just have a write method
784*cda5da8dSAndroid Build Coastguard Worker                    file = io.BufferedIOBase()
785*cda5da8dSAndroid Build Coastguard Worker                    file.writable = lambda: True
786*cda5da8dSAndroid Build Coastguard Worker                    file.write = write
787*cda5da8dSAndroid Build Coastguard Worker                    try:
788*cda5da8dSAndroid Build Coastguard Worker                        # TextIOWrapper uses this methods to determine
789*cda5da8dSAndroid Build Coastguard Worker                        # if BOM (for UTF-16, etc) should be added
790*cda5da8dSAndroid Build Coastguard Worker                        file.seekable = file_or_filename.seekable
791*cda5da8dSAndroid Build Coastguard Worker                        file.tell = file_or_filename.tell
792*cda5da8dSAndroid Build Coastguard Worker                    except AttributeError:
793*cda5da8dSAndroid Build Coastguard Worker                        pass
794*cda5da8dSAndroid Build Coastguard Worker                file = io.TextIOWrapper(file,
795*cda5da8dSAndroid Build Coastguard Worker                                        encoding=encoding,
796*cda5da8dSAndroid Build Coastguard Worker                                        errors="xmlcharrefreplace",
797*cda5da8dSAndroid Build Coastguard Worker                                        newline="\n")
798*cda5da8dSAndroid Build Coastguard Worker                # Keep the original file open when the TextIOWrapper is
799*cda5da8dSAndroid Build Coastguard Worker                # destroyed
800*cda5da8dSAndroid Build Coastguard Worker                stack.callback(file.detach)
801*cda5da8dSAndroid Build Coastguard Worker                yield file.write, encoding
802*cda5da8dSAndroid Build Coastguard Worker
803*cda5da8dSAndroid Build Coastguard Workerdef _namespaces(elem, default_namespace=None):
804*cda5da8dSAndroid Build Coastguard Worker    # identify namespaces used in this tree
805*cda5da8dSAndroid Build Coastguard Worker
806*cda5da8dSAndroid Build Coastguard Worker    # maps qnames to *encoded* prefix:local names
807*cda5da8dSAndroid Build Coastguard Worker    qnames = {None: None}
808*cda5da8dSAndroid Build Coastguard Worker
809*cda5da8dSAndroid Build Coastguard Worker    # maps uri:s to prefixes
810*cda5da8dSAndroid Build Coastguard Worker    namespaces = {}
811*cda5da8dSAndroid Build Coastguard Worker    if default_namespace:
812*cda5da8dSAndroid Build Coastguard Worker        namespaces[default_namespace] = ""
813*cda5da8dSAndroid Build Coastguard Worker
814*cda5da8dSAndroid Build Coastguard Worker    def add_qname(qname):
815*cda5da8dSAndroid Build Coastguard Worker        # calculate serialized qname representation
816*cda5da8dSAndroid Build Coastguard Worker        try:
817*cda5da8dSAndroid Build Coastguard Worker            if qname[:1] == "{":
818*cda5da8dSAndroid Build Coastguard Worker                uri, tag = qname[1:].rsplit("}", 1)
819*cda5da8dSAndroid Build Coastguard Worker                prefix = namespaces.get(uri)
820*cda5da8dSAndroid Build Coastguard Worker                if prefix is None:
821*cda5da8dSAndroid Build Coastguard Worker                    prefix = _namespace_map.get(uri)
822*cda5da8dSAndroid Build Coastguard Worker                    if prefix is None:
823*cda5da8dSAndroid Build Coastguard Worker                        prefix = "ns%d" % len(namespaces)
824*cda5da8dSAndroid Build Coastguard Worker                    if prefix != "xml":
825*cda5da8dSAndroid Build Coastguard Worker                        namespaces[uri] = prefix
826*cda5da8dSAndroid Build Coastguard Worker                if prefix:
827*cda5da8dSAndroid Build Coastguard Worker                    qnames[qname] = "%s:%s" % (prefix, tag)
828*cda5da8dSAndroid Build Coastguard Worker                else:
829*cda5da8dSAndroid Build Coastguard Worker                    qnames[qname] = tag # default element
830*cda5da8dSAndroid Build Coastguard Worker            else:
831*cda5da8dSAndroid Build Coastguard Worker                if default_namespace:
832*cda5da8dSAndroid Build Coastguard Worker                    # FIXME: can this be handled in XML 1.0?
833*cda5da8dSAndroid Build Coastguard Worker                    raise ValueError(
834*cda5da8dSAndroid Build Coastguard Worker                        "cannot use non-qualified names with "
835*cda5da8dSAndroid Build Coastguard Worker                        "default_namespace option"
836*cda5da8dSAndroid Build Coastguard Worker                        )
837*cda5da8dSAndroid Build Coastguard Worker                qnames[qname] = qname
838*cda5da8dSAndroid Build Coastguard Worker        except TypeError:
839*cda5da8dSAndroid Build Coastguard Worker            _raise_serialization_error(qname)
840*cda5da8dSAndroid Build Coastguard Worker
841*cda5da8dSAndroid Build Coastguard Worker    # populate qname and namespaces table
842*cda5da8dSAndroid Build Coastguard Worker    for elem in elem.iter():
843*cda5da8dSAndroid Build Coastguard Worker        tag = elem.tag
844*cda5da8dSAndroid Build Coastguard Worker        if isinstance(tag, QName):
845*cda5da8dSAndroid Build Coastguard Worker            if tag.text not in qnames:
846*cda5da8dSAndroid Build Coastguard Worker                add_qname(tag.text)
847*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(tag, str):
848*cda5da8dSAndroid Build Coastguard Worker            if tag not in qnames:
849*cda5da8dSAndroid Build Coastguard Worker                add_qname(tag)
850*cda5da8dSAndroid Build Coastguard Worker        elif tag is not None and tag is not Comment and tag is not PI:
851*cda5da8dSAndroid Build Coastguard Worker            _raise_serialization_error(tag)
852*cda5da8dSAndroid Build Coastguard Worker        for key, value in elem.items():
853*cda5da8dSAndroid Build Coastguard Worker            if isinstance(key, QName):
854*cda5da8dSAndroid Build Coastguard Worker                key = key.text
855*cda5da8dSAndroid Build Coastguard Worker            if key not in qnames:
856*cda5da8dSAndroid Build Coastguard Worker                add_qname(key)
857*cda5da8dSAndroid Build Coastguard Worker            if isinstance(value, QName) and value.text not in qnames:
858*cda5da8dSAndroid Build Coastguard Worker                add_qname(value.text)
859*cda5da8dSAndroid Build Coastguard Worker        text = elem.text
860*cda5da8dSAndroid Build Coastguard Worker        if isinstance(text, QName) and text.text not in qnames:
861*cda5da8dSAndroid Build Coastguard Worker            add_qname(text.text)
862*cda5da8dSAndroid Build Coastguard Worker    return qnames, namespaces
863*cda5da8dSAndroid Build Coastguard Worker
864*cda5da8dSAndroid Build Coastguard Workerdef _serialize_xml(write, elem, qnames, namespaces,
865*cda5da8dSAndroid Build Coastguard Worker                   short_empty_elements, **kwargs):
866*cda5da8dSAndroid Build Coastguard Worker    tag = elem.tag
867*cda5da8dSAndroid Build Coastguard Worker    text = elem.text
868*cda5da8dSAndroid Build Coastguard Worker    if tag is Comment:
869*cda5da8dSAndroid Build Coastguard Worker        write("<!--%s-->" % text)
870*cda5da8dSAndroid Build Coastguard Worker    elif tag is ProcessingInstruction:
871*cda5da8dSAndroid Build Coastguard Worker        write("<?%s?>" % text)
872*cda5da8dSAndroid Build Coastguard Worker    else:
873*cda5da8dSAndroid Build Coastguard Worker        tag = qnames[tag]
874*cda5da8dSAndroid Build Coastguard Worker        if tag is None:
875*cda5da8dSAndroid Build Coastguard Worker            if text:
876*cda5da8dSAndroid Build Coastguard Worker                write(_escape_cdata(text))
877*cda5da8dSAndroid Build Coastguard Worker            for e in elem:
878*cda5da8dSAndroid Build Coastguard Worker                _serialize_xml(write, e, qnames, None,
879*cda5da8dSAndroid Build Coastguard Worker                               short_empty_elements=short_empty_elements)
880*cda5da8dSAndroid Build Coastguard Worker        else:
881*cda5da8dSAndroid Build Coastguard Worker            write("<" + tag)
882*cda5da8dSAndroid Build Coastguard Worker            items = list(elem.items())
883*cda5da8dSAndroid Build Coastguard Worker            if items or namespaces:
884*cda5da8dSAndroid Build Coastguard Worker                if namespaces:
885*cda5da8dSAndroid Build Coastguard Worker                    for v, k in sorted(namespaces.items(),
886*cda5da8dSAndroid Build Coastguard Worker                                       key=lambda x: x[1]):  # sort on prefix
887*cda5da8dSAndroid Build Coastguard Worker                        if k:
888*cda5da8dSAndroid Build Coastguard Worker                            k = ":" + k
889*cda5da8dSAndroid Build Coastguard Worker                        write(" xmlns%s=\"%s\"" % (
890*cda5da8dSAndroid Build Coastguard Worker                            k,
891*cda5da8dSAndroid Build Coastguard Worker                            _escape_attrib(v)
892*cda5da8dSAndroid Build Coastguard Worker                            ))
893*cda5da8dSAndroid Build Coastguard Worker                for k, v in items:
894*cda5da8dSAndroid Build Coastguard Worker                    if isinstance(k, QName):
895*cda5da8dSAndroid Build Coastguard Worker                        k = k.text
896*cda5da8dSAndroid Build Coastguard Worker                    if isinstance(v, QName):
897*cda5da8dSAndroid Build Coastguard Worker                        v = qnames[v.text]
898*cda5da8dSAndroid Build Coastguard Worker                    else:
899*cda5da8dSAndroid Build Coastguard Worker                        v = _escape_attrib(v)
900*cda5da8dSAndroid Build Coastguard Worker                    write(" %s=\"%s\"" % (qnames[k], v))
901*cda5da8dSAndroid Build Coastguard Worker            if text or len(elem) or not short_empty_elements:
902*cda5da8dSAndroid Build Coastguard Worker                write(">")
903*cda5da8dSAndroid Build Coastguard Worker                if text:
904*cda5da8dSAndroid Build Coastguard Worker                    write(_escape_cdata(text))
905*cda5da8dSAndroid Build Coastguard Worker                for e in elem:
906*cda5da8dSAndroid Build Coastguard Worker                    _serialize_xml(write, e, qnames, None,
907*cda5da8dSAndroid Build Coastguard Worker                                   short_empty_elements=short_empty_elements)
908*cda5da8dSAndroid Build Coastguard Worker                write("</" + tag + ">")
909*cda5da8dSAndroid Build Coastguard Worker            else:
910*cda5da8dSAndroid Build Coastguard Worker                write(" />")
911*cda5da8dSAndroid Build Coastguard Worker    if elem.tail:
912*cda5da8dSAndroid Build Coastguard Worker        write(_escape_cdata(elem.tail))
913*cda5da8dSAndroid Build Coastguard Worker
914*cda5da8dSAndroid Build Coastguard WorkerHTML_EMPTY = {"area", "base", "basefont", "br", "col", "embed", "frame", "hr",
915*cda5da8dSAndroid Build Coastguard Worker              "img", "input", "isindex", "link", "meta", "param", "source",
916*cda5da8dSAndroid Build Coastguard Worker              "track", "wbr"}
917*cda5da8dSAndroid Build Coastguard Worker
918*cda5da8dSAndroid Build Coastguard Workerdef _serialize_html(write, elem, qnames, namespaces, **kwargs):
919*cda5da8dSAndroid Build Coastguard Worker    tag = elem.tag
920*cda5da8dSAndroid Build Coastguard Worker    text = elem.text
921*cda5da8dSAndroid Build Coastguard Worker    if tag is Comment:
922*cda5da8dSAndroid Build Coastguard Worker        write("<!--%s-->" % _escape_cdata(text))
923*cda5da8dSAndroid Build Coastguard Worker    elif tag is ProcessingInstruction:
924*cda5da8dSAndroid Build Coastguard Worker        write("<?%s?>" % _escape_cdata(text))
925*cda5da8dSAndroid Build Coastguard Worker    else:
926*cda5da8dSAndroid Build Coastguard Worker        tag = qnames[tag]
927*cda5da8dSAndroid Build Coastguard Worker        if tag is None:
928*cda5da8dSAndroid Build Coastguard Worker            if text:
929*cda5da8dSAndroid Build Coastguard Worker                write(_escape_cdata(text))
930*cda5da8dSAndroid Build Coastguard Worker            for e in elem:
931*cda5da8dSAndroid Build Coastguard Worker                _serialize_html(write, e, qnames, None)
932*cda5da8dSAndroid Build Coastguard Worker        else:
933*cda5da8dSAndroid Build Coastguard Worker            write("<" + tag)
934*cda5da8dSAndroid Build Coastguard Worker            items = list(elem.items())
935*cda5da8dSAndroid Build Coastguard Worker            if items or namespaces:
936*cda5da8dSAndroid Build Coastguard Worker                if namespaces:
937*cda5da8dSAndroid Build Coastguard Worker                    for v, k in sorted(namespaces.items(),
938*cda5da8dSAndroid Build Coastguard Worker                                       key=lambda x: x[1]):  # sort on prefix
939*cda5da8dSAndroid Build Coastguard Worker                        if k:
940*cda5da8dSAndroid Build Coastguard Worker                            k = ":" + k
941*cda5da8dSAndroid Build Coastguard Worker                        write(" xmlns%s=\"%s\"" % (
942*cda5da8dSAndroid Build Coastguard Worker                            k,
943*cda5da8dSAndroid Build Coastguard Worker                            _escape_attrib(v)
944*cda5da8dSAndroid Build Coastguard Worker                            ))
945*cda5da8dSAndroid Build Coastguard Worker                for k, v in items:
946*cda5da8dSAndroid Build Coastguard Worker                    if isinstance(k, QName):
947*cda5da8dSAndroid Build Coastguard Worker                        k = k.text
948*cda5da8dSAndroid Build Coastguard Worker                    if isinstance(v, QName):
949*cda5da8dSAndroid Build Coastguard Worker                        v = qnames[v.text]
950*cda5da8dSAndroid Build Coastguard Worker                    else:
951*cda5da8dSAndroid Build Coastguard Worker                        v = _escape_attrib_html(v)
952*cda5da8dSAndroid Build Coastguard Worker                    # FIXME: handle boolean attributes
953*cda5da8dSAndroid Build Coastguard Worker                    write(" %s=\"%s\"" % (qnames[k], v))
954*cda5da8dSAndroid Build Coastguard Worker            write(">")
955*cda5da8dSAndroid Build Coastguard Worker            ltag = tag.lower()
956*cda5da8dSAndroid Build Coastguard Worker            if text:
957*cda5da8dSAndroid Build Coastguard Worker                if ltag == "script" or ltag == "style":
958*cda5da8dSAndroid Build Coastguard Worker                    write(text)
959*cda5da8dSAndroid Build Coastguard Worker                else:
960*cda5da8dSAndroid Build Coastguard Worker                    write(_escape_cdata(text))
961*cda5da8dSAndroid Build Coastguard Worker            for e in elem:
962*cda5da8dSAndroid Build Coastguard Worker                _serialize_html(write, e, qnames, None)
963*cda5da8dSAndroid Build Coastguard Worker            if ltag not in HTML_EMPTY:
964*cda5da8dSAndroid Build Coastguard Worker                write("</" + tag + ">")
965*cda5da8dSAndroid Build Coastguard Worker    if elem.tail:
966*cda5da8dSAndroid Build Coastguard Worker        write(_escape_cdata(elem.tail))
967*cda5da8dSAndroid Build Coastguard Worker
968*cda5da8dSAndroid Build Coastguard Workerdef _serialize_text(write, elem):
969*cda5da8dSAndroid Build Coastguard Worker    for part in elem.itertext():
970*cda5da8dSAndroid Build Coastguard Worker        write(part)
971*cda5da8dSAndroid Build Coastguard Worker    if elem.tail:
972*cda5da8dSAndroid Build Coastguard Worker        write(elem.tail)
973*cda5da8dSAndroid Build Coastguard Worker
974*cda5da8dSAndroid Build Coastguard Worker_serialize = {
975*cda5da8dSAndroid Build Coastguard Worker    "xml": _serialize_xml,
976*cda5da8dSAndroid Build Coastguard Worker    "html": _serialize_html,
977*cda5da8dSAndroid Build Coastguard Worker    "text": _serialize_text,
978*cda5da8dSAndroid Build Coastguard Worker# this optional method is imported at the end of the module
979*cda5da8dSAndroid Build Coastguard Worker#   "c14n": _serialize_c14n,
980*cda5da8dSAndroid Build Coastguard Worker}
981*cda5da8dSAndroid Build Coastguard Worker
982*cda5da8dSAndroid Build Coastguard Worker
983*cda5da8dSAndroid Build Coastguard Workerdef register_namespace(prefix, uri):
984*cda5da8dSAndroid Build Coastguard Worker    """Register a namespace prefix.
985*cda5da8dSAndroid Build Coastguard Worker
986*cda5da8dSAndroid Build Coastguard Worker    The registry is global, and any existing mapping for either the
987*cda5da8dSAndroid Build Coastguard Worker    given prefix or the namespace URI will be removed.
988*cda5da8dSAndroid Build Coastguard Worker
989*cda5da8dSAndroid Build Coastguard Worker    *prefix* is the namespace prefix, *uri* is a namespace uri. Tags and
990*cda5da8dSAndroid Build Coastguard Worker    attributes in this namespace will be serialized with prefix if possible.
991*cda5da8dSAndroid Build Coastguard Worker
992*cda5da8dSAndroid Build Coastguard Worker    ValueError is raised if prefix is reserved or is invalid.
993*cda5da8dSAndroid Build Coastguard Worker
994*cda5da8dSAndroid Build Coastguard Worker    """
995*cda5da8dSAndroid Build Coastguard Worker    if re.match(r"ns\d+$", prefix):
996*cda5da8dSAndroid Build Coastguard Worker        raise ValueError("Prefix format reserved for internal use")
997*cda5da8dSAndroid Build Coastguard Worker    for k, v in list(_namespace_map.items()):
998*cda5da8dSAndroid Build Coastguard Worker        if k == uri or v == prefix:
999*cda5da8dSAndroid Build Coastguard Worker            del _namespace_map[k]
1000*cda5da8dSAndroid Build Coastguard Worker    _namespace_map[uri] = prefix
1001*cda5da8dSAndroid Build Coastguard Worker
1002*cda5da8dSAndroid Build Coastguard Worker_namespace_map = {
1003*cda5da8dSAndroid Build Coastguard Worker    # "well-known" namespace prefixes
1004*cda5da8dSAndroid Build Coastguard Worker    "http://www.w3.org/XML/1998/namespace": "xml",
1005*cda5da8dSAndroid Build Coastguard Worker    "http://www.w3.org/1999/xhtml": "html",
1006*cda5da8dSAndroid Build Coastguard Worker    "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
1007*cda5da8dSAndroid Build Coastguard Worker    "http://schemas.xmlsoap.org/wsdl/": "wsdl",
1008*cda5da8dSAndroid Build Coastguard Worker    # xml schema
1009*cda5da8dSAndroid Build Coastguard Worker    "http://www.w3.org/2001/XMLSchema": "xs",
1010*cda5da8dSAndroid Build Coastguard Worker    "http://www.w3.org/2001/XMLSchema-instance": "xsi",
1011*cda5da8dSAndroid Build Coastguard Worker    # dublin core
1012*cda5da8dSAndroid Build Coastguard Worker    "http://purl.org/dc/elements/1.1/": "dc",
1013*cda5da8dSAndroid Build Coastguard Worker}
1014*cda5da8dSAndroid Build Coastguard Worker# For tests and troubleshooting
1015*cda5da8dSAndroid Build Coastguard Workerregister_namespace._namespace_map = _namespace_map
1016*cda5da8dSAndroid Build Coastguard Worker
1017*cda5da8dSAndroid Build Coastguard Workerdef _raise_serialization_error(text):
1018*cda5da8dSAndroid Build Coastguard Worker    raise TypeError(
1019*cda5da8dSAndroid Build Coastguard Worker        "cannot serialize %r (type %s)" % (text, type(text).__name__)
1020*cda5da8dSAndroid Build Coastguard Worker        )
1021*cda5da8dSAndroid Build Coastguard Worker
1022*cda5da8dSAndroid Build Coastguard Workerdef _escape_cdata(text):
1023*cda5da8dSAndroid Build Coastguard Worker    # escape character data
1024*cda5da8dSAndroid Build Coastguard Worker    try:
1025*cda5da8dSAndroid Build Coastguard Worker        # it's worth avoiding do-nothing calls for strings that are
1026*cda5da8dSAndroid Build Coastguard Worker        # shorter than 500 characters, or so.  assume that's, by far,
1027*cda5da8dSAndroid Build Coastguard Worker        # the most common case in most applications.
1028*cda5da8dSAndroid Build Coastguard Worker        if "&" in text:
1029*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("&", "&amp;")
1030*cda5da8dSAndroid Build Coastguard Worker        if "<" in text:
1031*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("<", "&lt;")
1032*cda5da8dSAndroid Build Coastguard Worker        if ">" in text:
1033*cda5da8dSAndroid Build Coastguard Worker            text = text.replace(">", "&gt;")
1034*cda5da8dSAndroid Build Coastguard Worker        return text
1035*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError):
1036*cda5da8dSAndroid Build Coastguard Worker        _raise_serialization_error(text)
1037*cda5da8dSAndroid Build Coastguard Worker
1038*cda5da8dSAndroid Build Coastguard Workerdef _escape_attrib(text):
1039*cda5da8dSAndroid Build Coastguard Worker    # escape attribute value
1040*cda5da8dSAndroid Build Coastguard Worker    try:
1041*cda5da8dSAndroid Build Coastguard Worker        if "&" in text:
1042*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("&", "&amp;")
1043*cda5da8dSAndroid Build Coastguard Worker        if "<" in text:
1044*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("<", "&lt;")
1045*cda5da8dSAndroid Build Coastguard Worker        if ">" in text:
1046*cda5da8dSAndroid Build Coastguard Worker            text = text.replace(">", "&gt;")
1047*cda5da8dSAndroid Build Coastguard Worker        if "\"" in text:
1048*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("\"", "&quot;")
1049*cda5da8dSAndroid Build Coastguard Worker        # Although section 2.11 of the XML specification states that CR or
1050*cda5da8dSAndroid Build Coastguard Worker        # CR LN should be replaced with just LN, it applies only to EOLNs
1051*cda5da8dSAndroid Build Coastguard Worker        # which take part of organizing file into lines. Within attributes,
1052*cda5da8dSAndroid Build Coastguard Worker        # we are replacing these with entity numbers, so they do not count.
1053*cda5da8dSAndroid Build Coastguard Worker        # http://www.w3.org/TR/REC-xml/#sec-line-ends
1054*cda5da8dSAndroid Build Coastguard Worker        # The current solution, contained in following six lines, was
1055*cda5da8dSAndroid Build Coastguard Worker        # discussed in issue 17582 and 39011.
1056*cda5da8dSAndroid Build Coastguard Worker        if "\r" in text:
1057*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("\r", "&#13;")
1058*cda5da8dSAndroid Build Coastguard Worker        if "\n" in text:
1059*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("\n", "&#10;")
1060*cda5da8dSAndroid Build Coastguard Worker        if "\t" in text:
1061*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("\t", "&#09;")
1062*cda5da8dSAndroid Build Coastguard Worker        return text
1063*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError):
1064*cda5da8dSAndroid Build Coastguard Worker        _raise_serialization_error(text)
1065*cda5da8dSAndroid Build Coastguard Worker
1066*cda5da8dSAndroid Build Coastguard Workerdef _escape_attrib_html(text):
1067*cda5da8dSAndroid Build Coastguard Worker    # escape attribute value
1068*cda5da8dSAndroid Build Coastguard Worker    try:
1069*cda5da8dSAndroid Build Coastguard Worker        if "&" in text:
1070*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("&", "&amp;")
1071*cda5da8dSAndroid Build Coastguard Worker        if ">" in text:
1072*cda5da8dSAndroid Build Coastguard Worker            text = text.replace(">", "&gt;")
1073*cda5da8dSAndroid Build Coastguard Worker        if "\"" in text:
1074*cda5da8dSAndroid Build Coastguard Worker            text = text.replace("\"", "&quot;")
1075*cda5da8dSAndroid Build Coastguard Worker        return text
1076*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError):
1077*cda5da8dSAndroid Build Coastguard Worker        _raise_serialization_error(text)
1078*cda5da8dSAndroid Build Coastguard Worker
1079*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
1080*cda5da8dSAndroid Build Coastguard Worker
1081*cda5da8dSAndroid Build Coastguard Workerdef tostring(element, encoding=None, method=None, *,
1082*cda5da8dSAndroid Build Coastguard Worker             xml_declaration=None, default_namespace=None,
1083*cda5da8dSAndroid Build Coastguard Worker             short_empty_elements=True):
1084*cda5da8dSAndroid Build Coastguard Worker    """Generate string representation of XML element.
1085*cda5da8dSAndroid Build Coastguard Worker
1086*cda5da8dSAndroid Build Coastguard Worker    All subelements are included.  If encoding is "unicode", a string
1087*cda5da8dSAndroid Build Coastguard Worker    is returned. Otherwise a bytestring is returned.
1088*cda5da8dSAndroid Build Coastguard Worker
1089*cda5da8dSAndroid Build Coastguard Worker    *element* is an Element instance, *encoding* is an optional output
1090*cda5da8dSAndroid Build Coastguard Worker    encoding defaulting to US-ASCII, *method* is an optional output which can
1091*cda5da8dSAndroid Build Coastguard Worker    be one of "xml" (default), "html", "text" or "c14n", *default_namespace*
1092*cda5da8dSAndroid Build Coastguard Worker    sets the default XML namespace (for "xmlns").
1093*cda5da8dSAndroid Build Coastguard Worker
1094*cda5da8dSAndroid Build Coastguard Worker    Returns an (optionally) encoded string containing the XML data.
1095*cda5da8dSAndroid Build Coastguard Worker
1096*cda5da8dSAndroid Build Coastguard Worker    """
1097*cda5da8dSAndroid Build Coastguard Worker    stream = io.StringIO() if encoding == 'unicode' else io.BytesIO()
1098*cda5da8dSAndroid Build Coastguard Worker    ElementTree(element).write(stream, encoding,
1099*cda5da8dSAndroid Build Coastguard Worker                               xml_declaration=xml_declaration,
1100*cda5da8dSAndroid Build Coastguard Worker                               default_namespace=default_namespace,
1101*cda5da8dSAndroid Build Coastguard Worker                               method=method,
1102*cda5da8dSAndroid Build Coastguard Worker                               short_empty_elements=short_empty_elements)
1103*cda5da8dSAndroid Build Coastguard Worker    return stream.getvalue()
1104*cda5da8dSAndroid Build Coastguard Worker
1105*cda5da8dSAndroid Build Coastguard Workerclass _ListDataStream(io.BufferedIOBase):
1106*cda5da8dSAndroid Build Coastguard Worker    """An auxiliary stream accumulating into a list reference."""
1107*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, lst):
1108*cda5da8dSAndroid Build Coastguard Worker        self.lst = lst
1109*cda5da8dSAndroid Build Coastguard Worker
1110*cda5da8dSAndroid Build Coastguard Worker    def writable(self):
1111*cda5da8dSAndroid Build Coastguard Worker        return True
1112*cda5da8dSAndroid Build Coastguard Worker
1113*cda5da8dSAndroid Build Coastguard Worker    def seekable(self):
1114*cda5da8dSAndroid Build Coastguard Worker        return True
1115*cda5da8dSAndroid Build Coastguard Worker
1116*cda5da8dSAndroid Build Coastguard Worker    def write(self, b):
1117*cda5da8dSAndroid Build Coastguard Worker        self.lst.append(b)
1118*cda5da8dSAndroid Build Coastguard Worker
1119*cda5da8dSAndroid Build Coastguard Worker    def tell(self):
1120*cda5da8dSAndroid Build Coastguard Worker        return len(self.lst)
1121*cda5da8dSAndroid Build Coastguard Worker
1122*cda5da8dSAndroid Build Coastguard Workerdef tostringlist(element, encoding=None, method=None, *,
1123*cda5da8dSAndroid Build Coastguard Worker                 xml_declaration=None, default_namespace=None,
1124*cda5da8dSAndroid Build Coastguard Worker                 short_empty_elements=True):
1125*cda5da8dSAndroid Build Coastguard Worker    lst = []
1126*cda5da8dSAndroid Build Coastguard Worker    stream = _ListDataStream(lst)
1127*cda5da8dSAndroid Build Coastguard Worker    ElementTree(element).write(stream, encoding,
1128*cda5da8dSAndroid Build Coastguard Worker                               xml_declaration=xml_declaration,
1129*cda5da8dSAndroid Build Coastguard Worker                               default_namespace=default_namespace,
1130*cda5da8dSAndroid Build Coastguard Worker                               method=method,
1131*cda5da8dSAndroid Build Coastguard Worker                               short_empty_elements=short_empty_elements)
1132*cda5da8dSAndroid Build Coastguard Worker    return lst
1133*cda5da8dSAndroid Build Coastguard Worker
1134*cda5da8dSAndroid Build Coastguard Worker
1135*cda5da8dSAndroid Build Coastguard Workerdef dump(elem):
1136*cda5da8dSAndroid Build Coastguard Worker    """Write element tree or element structure to sys.stdout.
1137*cda5da8dSAndroid Build Coastguard Worker
1138*cda5da8dSAndroid Build Coastguard Worker    This function should be used for debugging only.
1139*cda5da8dSAndroid Build Coastguard Worker
1140*cda5da8dSAndroid Build Coastguard Worker    *elem* is either an ElementTree, or a single Element.  The exact output
1141*cda5da8dSAndroid Build Coastguard Worker    format is implementation dependent.  In this version, it's written as an
1142*cda5da8dSAndroid Build Coastguard Worker    ordinary XML file.
1143*cda5da8dSAndroid Build Coastguard Worker
1144*cda5da8dSAndroid Build Coastguard Worker    """
1145*cda5da8dSAndroid Build Coastguard Worker    # debugging
1146*cda5da8dSAndroid Build Coastguard Worker    if not isinstance(elem, ElementTree):
1147*cda5da8dSAndroid Build Coastguard Worker        elem = ElementTree(elem)
1148*cda5da8dSAndroid Build Coastguard Worker    elem.write(sys.stdout, encoding="unicode")
1149*cda5da8dSAndroid Build Coastguard Worker    tail = elem.getroot().tail
1150*cda5da8dSAndroid Build Coastguard Worker    if not tail or tail[-1] != "\n":
1151*cda5da8dSAndroid Build Coastguard Worker        sys.stdout.write("\n")
1152*cda5da8dSAndroid Build Coastguard Worker
1153*cda5da8dSAndroid Build Coastguard Worker
1154*cda5da8dSAndroid Build Coastguard Workerdef indent(tree, space="  ", level=0):
1155*cda5da8dSAndroid Build Coastguard Worker    """Indent an XML document by inserting newlines and indentation space
1156*cda5da8dSAndroid Build Coastguard Worker    after elements.
1157*cda5da8dSAndroid Build Coastguard Worker
1158*cda5da8dSAndroid Build Coastguard Worker    *tree* is the ElementTree or Element to modify.  The (root) element
1159*cda5da8dSAndroid Build Coastguard Worker    itself will not be changed, but the tail text of all elements in its
1160*cda5da8dSAndroid Build Coastguard Worker    subtree will be adapted.
1161*cda5da8dSAndroid Build Coastguard Worker
1162*cda5da8dSAndroid Build Coastguard Worker    *space* is the whitespace to insert for each indentation level, two
1163*cda5da8dSAndroid Build Coastguard Worker    space characters by default.
1164*cda5da8dSAndroid Build Coastguard Worker
1165*cda5da8dSAndroid Build Coastguard Worker    *level* is the initial indentation level. Setting this to a higher
1166*cda5da8dSAndroid Build Coastguard Worker    value than 0 can be used for indenting subtrees that are more deeply
1167*cda5da8dSAndroid Build Coastguard Worker    nested inside of a document.
1168*cda5da8dSAndroid Build Coastguard Worker    """
1169*cda5da8dSAndroid Build Coastguard Worker    if isinstance(tree, ElementTree):
1170*cda5da8dSAndroid Build Coastguard Worker        tree = tree.getroot()
1171*cda5da8dSAndroid Build Coastguard Worker    if level < 0:
1172*cda5da8dSAndroid Build Coastguard Worker        raise ValueError(f"Initial indentation level must be >= 0, got {level}")
1173*cda5da8dSAndroid Build Coastguard Worker    if not len(tree):
1174*cda5da8dSAndroid Build Coastguard Worker        return
1175*cda5da8dSAndroid Build Coastguard Worker
1176*cda5da8dSAndroid Build Coastguard Worker    # Reduce the memory consumption by reusing indentation strings.
1177*cda5da8dSAndroid Build Coastguard Worker    indentations = ["\n" + level * space]
1178*cda5da8dSAndroid Build Coastguard Worker
1179*cda5da8dSAndroid Build Coastguard Worker    def _indent_children(elem, level):
1180*cda5da8dSAndroid Build Coastguard Worker        # Start a new indentation level for the first child.
1181*cda5da8dSAndroid Build Coastguard Worker        child_level = level + 1
1182*cda5da8dSAndroid Build Coastguard Worker        try:
1183*cda5da8dSAndroid Build Coastguard Worker            child_indentation = indentations[child_level]
1184*cda5da8dSAndroid Build Coastguard Worker        except IndexError:
1185*cda5da8dSAndroid Build Coastguard Worker            child_indentation = indentations[level] + space
1186*cda5da8dSAndroid Build Coastguard Worker            indentations.append(child_indentation)
1187*cda5da8dSAndroid Build Coastguard Worker
1188*cda5da8dSAndroid Build Coastguard Worker        if not elem.text or not elem.text.strip():
1189*cda5da8dSAndroid Build Coastguard Worker            elem.text = child_indentation
1190*cda5da8dSAndroid Build Coastguard Worker
1191*cda5da8dSAndroid Build Coastguard Worker        for child in elem:
1192*cda5da8dSAndroid Build Coastguard Worker            if len(child):
1193*cda5da8dSAndroid Build Coastguard Worker                _indent_children(child, child_level)
1194*cda5da8dSAndroid Build Coastguard Worker            if not child.tail or not child.tail.strip():
1195*cda5da8dSAndroid Build Coastguard Worker                child.tail = child_indentation
1196*cda5da8dSAndroid Build Coastguard Worker
1197*cda5da8dSAndroid Build Coastguard Worker        # Dedent after the last child by overwriting the previous indentation.
1198*cda5da8dSAndroid Build Coastguard Worker        if not child.tail.strip():
1199*cda5da8dSAndroid Build Coastguard Worker            child.tail = indentations[level]
1200*cda5da8dSAndroid Build Coastguard Worker
1201*cda5da8dSAndroid Build Coastguard Worker    _indent_children(tree, 0)
1202*cda5da8dSAndroid Build Coastguard Worker
1203*cda5da8dSAndroid Build Coastguard Worker
1204*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
1205*cda5da8dSAndroid Build Coastguard Worker# parsing
1206*cda5da8dSAndroid Build Coastguard Worker
1207*cda5da8dSAndroid Build Coastguard Worker
1208*cda5da8dSAndroid Build Coastguard Workerdef parse(source, parser=None):
1209*cda5da8dSAndroid Build Coastguard Worker    """Parse XML document into element tree.
1210*cda5da8dSAndroid Build Coastguard Worker
1211*cda5da8dSAndroid Build Coastguard Worker    *source* is a filename or file object containing XML data,
1212*cda5da8dSAndroid Build Coastguard Worker    *parser* is an optional parser instance defaulting to XMLParser.
1213*cda5da8dSAndroid Build Coastguard Worker
1214*cda5da8dSAndroid Build Coastguard Worker    Return an ElementTree instance.
1215*cda5da8dSAndroid Build Coastguard Worker
1216*cda5da8dSAndroid Build Coastguard Worker    """
1217*cda5da8dSAndroid Build Coastguard Worker    tree = ElementTree()
1218*cda5da8dSAndroid Build Coastguard Worker    tree.parse(source, parser)
1219*cda5da8dSAndroid Build Coastguard Worker    return tree
1220*cda5da8dSAndroid Build Coastguard Worker
1221*cda5da8dSAndroid Build Coastguard Worker
1222*cda5da8dSAndroid Build Coastguard Workerdef iterparse(source, events=None, parser=None):
1223*cda5da8dSAndroid Build Coastguard Worker    """Incrementally parse XML document into ElementTree.
1224*cda5da8dSAndroid Build Coastguard Worker
1225*cda5da8dSAndroid Build Coastguard Worker    This class also reports what's going on to the user based on the
1226*cda5da8dSAndroid Build Coastguard Worker    *events* it is initialized with.  The supported events are the strings
1227*cda5da8dSAndroid Build Coastguard Worker    "start", "end", "start-ns" and "end-ns" (the "ns" events are used to get
1228*cda5da8dSAndroid Build Coastguard Worker    detailed namespace information).  If *events* is omitted, only
1229*cda5da8dSAndroid Build Coastguard Worker    "end" events are reported.
1230*cda5da8dSAndroid Build Coastguard Worker
1231*cda5da8dSAndroid Build Coastguard Worker    *source* is a filename or file object containing XML data, *events* is
1232*cda5da8dSAndroid Build Coastguard Worker    a list of events to report back, *parser* is an optional parser instance.
1233*cda5da8dSAndroid Build Coastguard Worker
1234*cda5da8dSAndroid Build Coastguard Worker    Returns an iterator providing (event, elem) pairs.
1235*cda5da8dSAndroid Build Coastguard Worker
1236*cda5da8dSAndroid Build Coastguard Worker    """
1237*cda5da8dSAndroid Build Coastguard Worker    # Use the internal, undocumented _parser argument for now; When the
1238*cda5da8dSAndroid Build Coastguard Worker    # parser argument of iterparse is removed, this can be killed.
1239*cda5da8dSAndroid Build Coastguard Worker    pullparser = XMLPullParser(events=events, _parser=parser)
1240*cda5da8dSAndroid Build Coastguard Worker
1241*cda5da8dSAndroid Build Coastguard Worker    def iterator(source):
1242*cda5da8dSAndroid Build Coastguard Worker        close_source = False
1243*cda5da8dSAndroid Build Coastguard Worker        try:
1244*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(source, "read"):
1245*cda5da8dSAndroid Build Coastguard Worker                source = open(source, "rb")
1246*cda5da8dSAndroid Build Coastguard Worker                close_source = True
1247*cda5da8dSAndroid Build Coastguard Worker            yield None
1248*cda5da8dSAndroid Build Coastguard Worker            while True:
1249*cda5da8dSAndroid Build Coastguard Worker                yield from pullparser.read_events()
1250*cda5da8dSAndroid Build Coastguard Worker                # load event buffer
1251*cda5da8dSAndroid Build Coastguard Worker                data = source.read(16 * 1024)
1252*cda5da8dSAndroid Build Coastguard Worker                if not data:
1253*cda5da8dSAndroid Build Coastguard Worker                    break
1254*cda5da8dSAndroid Build Coastguard Worker                pullparser.feed(data)
1255*cda5da8dSAndroid Build Coastguard Worker            root = pullparser._close_and_return_root()
1256*cda5da8dSAndroid Build Coastguard Worker            yield from pullparser.read_events()
1257*cda5da8dSAndroid Build Coastguard Worker            it.root = root
1258*cda5da8dSAndroid Build Coastguard Worker        finally:
1259*cda5da8dSAndroid Build Coastguard Worker            if close_source:
1260*cda5da8dSAndroid Build Coastguard Worker                source.close()
1261*cda5da8dSAndroid Build Coastguard Worker
1262*cda5da8dSAndroid Build Coastguard Worker    class IterParseIterator(collections.abc.Iterator):
1263*cda5da8dSAndroid Build Coastguard Worker        __next__ = iterator(source).__next__
1264*cda5da8dSAndroid Build Coastguard Worker    it = IterParseIterator()
1265*cda5da8dSAndroid Build Coastguard Worker    it.root = None
1266*cda5da8dSAndroid Build Coastguard Worker    del iterator, IterParseIterator
1267*cda5da8dSAndroid Build Coastguard Worker
1268*cda5da8dSAndroid Build Coastguard Worker    next(it)
1269*cda5da8dSAndroid Build Coastguard Worker    return it
1270*cda5da8dSAndroid Build Coastguard Worker
1271*cda5da8dSAndroid Build Coastguard Worker
1272*cda5da8dSAndroid Build Coastguard Workerclass XMLPullParser:
1273*cda5da8dSAndroid Build Coastguard Worker
1274*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, events=None, *, _parser=None):
1275*cda5da8dSAndroid Build Coastguard Worker        # The _parser argument is for internal use only and must not be relied
1276*cda5da8dSAndroid Build Coastguard Worker        # upon in user code. It will be removed in a future release.
1277*cda5da8dSAndroid Build Coastguard Worker        # See https://bugs.python.org/issue17741 for more details.
1278*cda5da8dSAndroid Build Coastguard Worker
1279*cda5da8dSAndroid Build Coastguard Worker        self._events_queue = collections.deque()
1280*cda5da8dSAndroid Build Coastguard Worker        self._parser = _parser or XMLParser(target=TreeBuilder())
1281*cda5da8dSAndroid Build Coastguard Worker        # wire up the parser for event reporting
1282*cda5da8dSAndroid Build Coastguard Worker        if events is None:
1283*cda5da8dSAndroid Build Coastguard Worker            events = ("end",)
1284*cda5da8dSAndroid Build Coastguard Worker        self._parser._setevents(self._events_queue, events)
1285*cda5da8dSAndroid Build Coastguard Worker
1286*cda5da8dSAndroid Build Coastguard Worker    def feed(self, data):
1287*cda5da8dSAndroid Build Coastguard Worker        """Feed encoded data to parser."""
1288*cda5da8dSAndroid Build Coastguard Worker        if self._parser is None:
1289*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("feed() called after end of stream")
1290*cda5da8dSAndroid Build Coastguard Worker        if data:
1291*cda5da8dSAndroid Build Coastguard Worker            try:
1292*cda5da8dSAndroid Build Coastguard Worker                self._parser.feed(data)
1293*cda5da8dSAndroid Build Coastguard Worker            except SyntaxError as exc:
1294*cda5da8dSAndroid Build Coastguard Worker                self._events_queue.append(exc)
1295*cda5da8dSAndroid Build Coastguard Worker
1296*cda5da8dSAndroid Build Coastguard Worker    def _close_and_return_root(self):
1297*cda5da8dSAndroid Build Coastguard Worker        # iterparse needs this to set its root attribute properly :(
1298*cda5da8dSAndroid Build Coastguard Worker        root = self._parser.close()
1299*cda5da8dSAndroid Build Coastguard Worker        self._parser = None
1300*cda5da8dSAndroid Build Coastguard Worker        return root
1301*cda5da8dSAndroid Build Coastguard Worker
1302*cda5da8dSAndroid Build Coastguard Worker    def close(self):
1303*cda5da8dSAndroid Build Coastguard Worker        """Finish feeding data to parser.
1304*cda5da8dSAndroid Build Coastguard Worker
1305*cda5da8dSAndroid Build Coastguard Worker        Unlike XMLParser, does not return the root element. Use
1306*cda5da8dSAndroid Build Coastguard Worker        read_events() to consume elements from XMLPullParser.
1307*cda5da8dSAndroid Build Coastguard Worker        """
1308*cda5da8dSAndroid Build Coastguard Worker        self._close_and_return_root()
1309*cda5da8dSAndroid Build Coastguard Worker
1310*cda5da8dSAndroid Build Coastguard Worker    def read_events(self):
1311*cda5da8dSAndroid Build Coastguard Worker        """Return an iterator over currently available (event, elem) pairs.
1312*cda5da8dSAndroid Build Coastguard Worker
1313*cda5da8dSAndroid Build Coastguard Worker        Events are consumed from the internal event queue as they are
1314*cda5da8dSAndroid Build Coastguard Worker        retrieved from the iterator.
1315*cda5da8dSAndroid Build Coastguard Worker        """
1316*cda5da8dSAndroid Build Coastguard Worker        events = self._events_queue
1317*cda5da8dSAndroid Build Coastguard Worker        while events:
1318*cda5da8dSAndroid Build Coastguard Worker            event = events.popleft()
1319*cda5da8dSAndroid Build Coastguard Worker            if isinstance(event, Exception):
1320*cda5da8dSAndroid Build Coastguard Worker                raise event
1321*cda5da8dSAndroid Build Coastguard Worker            else:
1322*cda5da8dSAndroid Build Coastguard Worker                yield event
1323*cda5da8dSAndroid Build Coastguard Worker
1324*cda5da8dSAndroid Build Coastguard Worker
1325*cda5da8dSAndroid Build Coastguard Workerdef XML(text, parser=None):
1326*cda5da8dSAndroid Build Coastguard Worker    """Parse XML document from string constant.
1327*cda5da8dSAndroid Build Coastguard Worker
1328*cda5da8dSAndroid Build Coastguard Worker    This function can be used to embed "XML Literals" in Python code.
1329*cda5da8dSAndroid Build Coastguard Worker
1330*cda5da8dSAndroid Build Coastguard Worker    *text* is a string containing XML data, *parser* is an
1331*cda5da8dSAndroid Build Coastguard Worker    optional parser instance, defaulting to the standard XMLParser.
1332*cda5da8dSAndroid Build Coastguard Worker
1333*cda5da8dSAndroid Build Coastguard Worker    Returns an Element instance.
1334*cda5da8dSAndroid Build Coastguard Worker
1335*cda5da8dSAndroid Build Coastguard Worker    """
1336*cda5da8dSAndroid Build Coastguard Worker    if not parser:
1337*cda5da8dSAndroid Build Coastguard Worker        parser = XMLParser(target=TreeBuilder())
1338*cda5da8dSAndroid Build Coastguard Worker    parser.feed(text)
1339*cda5da8dSAndroid Build Coastguard Worker    return parser.close()
1340*cda5da8dSAndroid Build Coastguard Worker
1341*cda5da8dSAndroid Build Coastguard Worker
1342*cda5da8dSAndroid Build Coastguard Workerdef XMLID(text, parser=None):
1343*cda5da8dSAndroid Build Coastguard Worker    """Parse XML document from string constant for its IDs.
1344*cda5da8dSAndroid Build Coastguard Worker
1345*cda5da8dSAndroid Build Coastguard Worker    *text* is a string containing XML data, *parser* is an
1346*cda5da8dSAndroid Build Coastguard Worker    optional parser instance, defaulting to the standard XMLParser.
1347*cda5da8dSAndroid Build Coastguard Worker
1348*cda5da8dSAndroid Build Coastguard Worker    Returns an (Element, dict) tuple, in which the
1349*cda5da8dSAndroid Build Coastguard Worker    dict maps element id:s to elements.
1350*cda5da8dSAndroid Build Coastguard Worker
1351*cda5da8dSAndroid Build Coastguard Worker    """
1352*cda5da8dSAndroid Build Coastguard Worker    if not parser:
1353*cda5da8dSAndroid Build Coastguard Worker        parser = XMLParser(target=TreeBuilder())
1354*cda5da8dSAndroid Build Coastguard Worker    parser.feed(text)
1355*cda5da8dSAndroid Build Coastguard Worker    tree = parser.close()
1356*cda5da8dSAndroid Build Coastguard Worker    ids = {}
1357*cda5da8dSAndroid Build Coastguard Worker    for elem in tree.iter():
1358*cda5da8dSAndroid Build Coastguard Worker        id = elem.get("id")
1359*cda5da8dSAndroid Build Coastguard Worker        if id:
1360*cda5da8dSAndroid Build Coastguard Worker            ids[id] = elem
1361*cda5da8dSAndroid Build Coastguard Worker    return tree, ids
1362*cda5da8dSAndroid Build Coastguard Worker
1363*cda5da8dSAndroid Build Coastguard Worker# Parse XML document from string constant.  Alias for XML().
1364*cda5da8dSAndroid Build Coastguard Workerfromstring = XML
1365*cda5da8dSAndroid Build Coastguard Worker
1366*cda5da8dSAndroid Build Coastguard Workerdef fromstringlist(sequence, parser=None):
1367*cda5da8dSAndroid Build Coastguard Worker    """Parse XML document from sequence of string fragments.
1368*cda5da8dSAndroid Build Coastguard Worker
1369*cda5da8dSAndroid Build Coastguard Worker    *sequence* is a list of other sequence, *parser* is an optional parser
1370*cda5da8dSAndroid Build Coastguard Worker    instance, defaulting to the standard XMLParser.
1371*cda5da8dSAndroid Build Coastguard Worker
1372*cda5da8dSAndroid Build Coastguard Worker    Returns an Element instance.
1373*cda5da8dSAndroid Build Coastguard Worker
1374*cda5da8dSAndroid Build Coastguard Worker    """
1375*cda5da8dSAndroid Build Coastguard Worker    if not parser:
1376*cda5da8dSAndroid Build Coastguard Worker        parser = XMLParser(target=TreeBuilder())
1377*cda5da8dSAndroid Build Coastguard Worker    for text in sequence:
1378*cda5da8dSAndroid Build Coastguard Worker        parser.feed(text)
1379*cda5da8dSAndroid Build Coastguard Worker    return parser.close()
1380*cda5da8dSAndroid Build Coastguard Worker
1381*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
1382*cda5da8dSAndroid Build Coastguard Worker
1383*cda5da8dSAndroid Build Coastguard Worker
1384*cda5da8dSAndroid Build Coastguard Workerclass TreeBuilder:
1385*cda5da8dSAndroid Build Coastguard Worker    """Generic element structure builder.
1386*cda5da8dSAndroid Build Coastguard Worker
1387*cda5da8dSAndroid Build Coastguard Worker    This builder converts a sequence of start, data, and end method
1388*cda5da8dSAndroid Build Coastguard Worker    calls to a well-formed element structure.
1389*cda5da8dSAndroid Build Coastguard Worker
1390*cda5da8dSAndroid Build Coastguard Worker    You can use this class to build an element structure using a custom XML
1391*cda5da8dSAndroid Build Coastguard Worker    parser, or a parser for some other XML-like format.
1392*cda5da8dSAndroid Build Coastguard Worker
1393*cda5da8dSAndroid Build Coastguard Worker    *element_factory* is an optional element factory which is called
1394*cda5da8dSAndroid Build Coastguard Worker    to create new Element instances, as necessary.
1395*cda5da8dSAndroid Build Coastguard Worker
1396*cda5da8dSAndroid Build Coastguard Worker    *comment_factory* is a factory to create comments to be used instead of
1397*cda5da8dSAndroid Build Coastguard Worker    the standard factory.  If *insert_comments* is false (the default),
1398*cda5da8dSAndroid Build Coastguard Worker    comments will not be inserted into the tree.
1399*cda5da8dSAndroid Build Coastguard Worker
1400*cda5da8dSAndroid Build Coastguard Worker    *pi_factory* is a factory to create processing instructions to be used
1401*cda5da8dSAndroid Build Coastguard Worker    instead of the standard factory.  If *insert_pis* is false (the default),
1402*cda5da8dSAndroid Build Coastguard Worker    processing instructions will not be inserted into the tree.
1403*cda5da8dSAndroid Build Coastguard Worker    """
1404*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, element_factory=None, *,
1405*cda5da8dSAndroid Build Coastguard Worker                 comment_factory=None, pi_factory=None,
1406*cda5da8dSAndroid Build Coastguard Worker                 insert_comments=False, insert_pis=False):
1407*cda5da8dSAndroid Build Coastguard Worker        self._data = [] # data collector
1408*cda5da8dSAndroid Build Coastguard Worker        self._elem = [] # element stack
1409*cda5da8dSAndroid Build Coastguard Worker        self._last = None # last element
1410*cda5da8dSAndroid Build Coastguard Worker        self._root = None # root element
1411*cda5da8dSAndroid Build Coastguard Worker        self._tail = None # true if we're after an end tag
1412*cda5da8dSAndroid Build Coastguard Worker        if comment_factory is None:
1413*cda5da8dSAndroid Build Coastguard Worker            comment_factory = Comment
1414*cda5da8dSAndroid Build Coastguard Worker        self._comment_factory = comment_factory
1415*cda5da8dSAndroid Build Coastguard Worker        self.insert_comments = insert_comments
1416*cda5da8dSAndroid Build Coastguard Worker        if pi_factory is None:
1417*cda5da8dSAndroid Build Coastguard Worker            pi_factory = ProcessingInstruction
1418*cda5da8dSAndroid Build Coastguard Worker        self._pi_factory = pi_factory
1419*cda5da8dSAndroid Build Coastguard Worker        self.insert_pis = insert_pis
1420*cda5da8dSAndroid Build Coastguard Worker        if element_factory is None:
1421*cda5da8dSAndroid Build Coastguard Worker            element_factory = Element
1422*cda5da8dSAndroid Build Coastguard Worker        self._factory = element_factory
1423*cda5da8dSAndroid Build Coastguard Worker
1424*cda5da8dSAndroid Build Coastguard Worker    def close(self):
1425*cda5da8dSAndroid Build Coastguard Worker        """Flush builder buffers and return toplevel document Element."""
1426*cda5da8dSAndroid Build Coastguard Worker        assert len(self._elem) == 0, "missing end tags"
1427*cda5da8dSAndroid Build Coastguard Worker        assert self._root is not None, "missing toplevel element"
1428*cda5da8dSAndroid Build Coastguard Worker        return self._root
1429*cda5da8dSAndroid Build Coastguard Worker
1430*cda5da8dSAndroid Build Coastguard Worker    def _flush(self):
1431*cda5da8dSAndroid Build Coastguard Worker        if self._data:
1432*cda5da8dSAndroid Build Coastguard Worker            if self._last is not None:
1433*cda5da8dSAndroid Build Coastguard Worker                text = "".join(self._data)
1434*cda5da8dSAndroid Build Coastguard Worker                if self._tail:
1435*cda5da8dSAndroid Build Coastguard Worker                    assert self._last.tail is None, "internal error (tail)"
1436*cda5da8dSAndroid Build Coastguard Worker                    self._last.tail = text
1437*cda5da8dSAndroid Build Coastguard Worker                else:
1438*cda5da8dSAndroid Build Coastguard Worker                    assert self._last.text is None, "internal error (text)"
1439*cda5da8dSAndroid Build Coastguard Worker                    self._last.text = text
1440*cda5da8dSAndroid Build Coastguard Worker            self._data = []
1441*cda5da8dSAndroid Build Coastguard Worker
1442*cda5da8dSAndroid Build Coastguard Worker    def data(self, data):
1443*cda5da8dSAndroid Build Coastguard Worker        """Add text to current element."""
1444*cda5da8dSAndroid Build Coastguard Worker        self._data.append(data)
1445*cda5da8dSAndroid Build Coastguard Worker
1446*cda5da8dSAndroid Build Coastguard Worker    def start(self, tag, attrs):
1447*cda5da8dSAndroid Build Coastguard Worker        """Open new element and return it.
1448*cda5da8dSAndroid Build Coastguard Worker
1449*cda5da8dSAndroid Build Coastguard Worker        *tag* is the element name, *attrs* is a dict containing element
1450*cda5da8dSAndroid Build Coastguard Worker        attributes.
1451*cda5da8dSAndroid Build Coastguard Worker
1452*cda5da8dSAndroid Build Coastguard Worker        """
1453*cda5da8dSAndroid Build Coastguard Worker        self._flush()
1454*cda5da8dSAndroid Build Coastguard Worker        self._last = elem = self._factory(tag, attrs)
1455*cda5da8dSAndroid Build Coastguard Worker        if self._elem:
1456*cda5da8dSAndroid Build Coastguard Worker            self._elem[-1].append(elem)
1457*cda5da8dSAndroid Build Coastguard Worker        elif self._root is None:
1458*cda5da8dSAndroid Build Coastguard Worker            self._root = elem
1459*cda5da8dSAndroid Build Coastguard Worker        self._elem.append(elem)
1460*cda5da8dSAndroid Build Coastguard Worker        self._tail = 0
1461*cda5da8dSAndroid Build Coastguard Worker        return elem
1462*cda5da8dSAndroid Build Coastguard Worker
1463*cda5da8dSAndroid Build Coastguard Worker    def end(self, tag):
1464*cda5da8dSAndroid Build Coastguard Worker        """Close and return current Element.
1465*cda5da8dSAndroid Build Coastguard Worker
1466*cda5da8dSAndroid Build Coastguard Worker        *tag* is the element name.
1467*cda5da8dSAndroid Build Coastguard Worker
1468*cda5da8dSAndroid Build Coastguard Worker        """
1469*cda5da8dSAndroid Build Coastguard Worker        self._flush()
1470*cda5da8dSAndroid Build Coastguard Worker        self._last = self._elem.pop()
1471*cda5da8dSAndroid Build Coastguard Worker        assert self._last.tag == tag,\
1472*cda5da8dSAndroid Build Coastguard Worker               "end tag mismatch (expected %s, got %s)" % (
1473*cda5da8dSAndroid Build Coastguard Worker                   self._last.tag, tag)
1474*cda5da8dSAndroid Build Coastguard Worker        self._tail = 1
1475*cda5da8dSAndroid Build Coastguard Worker        return self._last
1476*cda5da8dSAndroid Build Coastguard Worker
1477*cda5da8dSAndroid Build Coastguard Worker    def comment(self, text):
1478*cda5da8dSAndroid Build Coastguard Worker        """Create a comment using the comment_factory.
1479*cda5da8dSAndroid Build Coastguard Worker
1480*cda5da8dSAndroid Build Coastguard Worker        *text* is the text of the comment.
1481*cda5da8dSAndroid Build Coastguard Worker        """
1482*cda5da8dSAndroid Build Coastguard Worker        return self._handle_single(
1483*cda5da8dSAndroid Build Coastguard Worker            self._comment_factory, self.insert_comments, text)
1484*cda5da8dSAndroid Build Coastguard Worker
1485*cda5da8dSAndroid Build Coastguard Worker    def pi(self, target, text=None):
1486*cda5da8dSAndroid Build Coastguard Worker        """Create a processing instruction using the pi_factory.
1487*cda5da8dSAndroid Build Coastguard Worker
1488*cda5da8dSAndroid Build Coastguard Worker        *target* is the target name of the processing instruction.
1489*cda5da8dSAndroid Build Coastguard Worker        *text* is the data of the processing instruction, or ''.
1490*cda5da8dSAndroid Build Coastguard Worker        """
1491*cda5da8dSAndroid Build Coastguard Worker        return self._handle_single(
1492*cda5da8dSAndroid Build Coastguard Worker            self._pi_factory, self.insert_pis, target, text)
1493*cda5da8dSAndroid Build Coastguard Worker
1494*cda5da8dSAndroid Build Coastguard Worker    def _handle_single(self, factory, insert, *args):
1495*cda5da8dSAndroid Build Coastguard Worker        elem = factory(*args)
1496*cda5da8dSAndroid Build Coastguard Worker        if insert:
1497*cda5da8dSAndroid Build Coastguard Worker            self._flush()
1498*cda5da8dSAndroid Build Coastguard Worker            self._last = elem
1499*cda5da8dSAndroid Build Coastguard Worker            if self._elem:
1500*cda5da8dSAndroid Build Coastguard Worker                self._elem[-1].append(elem)
1501*cda5da8dSAndroid Build Coastguard Worker            self._tail = 1
1502*cda5da8dSAndroid Build Coastguard Worker        return elem
1503*cda5da8dSAndroid Build Coastguard Worker
1504*cda5da8dSAndroid Build Coastguard Worker
1505*cda5da8dSAndroid Build Coastguard Worker# also see ElementTree and TreeBuilder
1506*cda5da8dSAndroid Build Coastguard Workerclass XMLParser:
1507*cda5da8dSAndroid Build Coastguard Worker    """Element structure builder for XML source data based on the expat parser.
1508*cda5da8dSAndroid Build Coastguard Worker
1509*cda5da8dSAndroid Build Coastguard Worker    *target* is an optional target object which defaults to an instance of the
1510*cda5da8dSAndroid Build Coastguard Worker    standard TreeBuilder class, *encoding* is an optional encoding string
1511*cda5da8dSAndroid Build Coastguard Worker    which if given, overrides the encoding specified in the XML file:
1512*cda5da8dSAndroid Build Coastguard Worker    http://www.iana.org/assignments/character-sets
1513*cda5da8dSAndroid Build Coastguard Worker
1514*cda5da8dSAndroid Build Coastguard Worker    """
1515*cda5da8dSAndroid Build Coastguard Worker
1516*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, *, target=None, encoding=None):
1517*cda5da8dSAndroid Build Coastguard Worker        try:
1518*cda5da8dSAndroid Build Coastguard Worker            from xml.parsers import expat
1519*cda5da8dSAndroid Build Coastguard Worker        except ImportError:
1520*cda5da8dSAndroid Build Coastguard Worker            try:
1521*cda5da8dSAndroid Build Coastguard Worker                import pyexpat as expat
1522*cda5da8dSAndroid Build Coastguard Worker            except ImportError:
1523*cda5da8dSAndroid Build Coastguard Worker                raise ImportError(
1524*cda5da8dSAndroid Build Coastguard Worker                    "No module named expat; use SimpleXMLTreeBuilder instead"
1525*cda5da8dSAndroid Build Coastguard Worker                    )
1526*cda5da8dSAndroid Build Coastguard Worker        parser = expat.ParserCreate(encoding, "}")
1527*cda5da8dSAndroid Build Coastguard Worker        if target is None:
1528*cda5da8dSAndroid Build Coastguard Worker            target = TreeBuilder()
1529*cda5da8dSAndroid Build Coastguard Worker        # underscored names are provided for compatibility only
1530*cda5da8dSAndroid Build Coastguard Worker        self.parser = self._parser = parser
1531*cda5da8dSAndroid Build Coastguard Worker        self.target = self._target = target
1532*cda5da8dSAndroid Build Coastguard Worker        self._error = expat.error
1533*cda5da8dSAndroid Build Coastguard Worker        self._names = {} # name memo cache
1534*cda5da8dSAndroid Build Coastguard Worker        # main callbacks
1535*cda5da8dSAndroid Build Coastguard Worker        parser.DefaultHandlerExpand = self._default
1536*cda5da8dSAndroid Build Coastguard Worker        if hasattr(target, 'start'):
1537*cda5da8dSAndroid Build Coastguard Worker            parser.StartElementHandler = self._start
1538*cda5da8dSAndroid Build Coastguard Worker        if hasattr(target, 'end'):
1539*cda5da8dSAndroid Build Coastguard Worker            parser.EndElementHandler = self._end
1540*cda5da8dSAndroid Build Coastguard Worker        if hasattr(target, 'start_ns'):
1541*cda5da8dSAndroid Build Coastguard Worker            parser.StartNamespaceDeclHandler = self._start_ns
1542*cda5da8dSAndroid Build Coastguard Worker        if hasattr(target, 'end_ns'):
1543*cda5da8dSAndroid Build Coastguard Worker            parser.EndNamespaceDeclHandler = self._end_ns
1544*cda5da8dSAndroid Build Coastguard Worker        if hasattr(target, 'data'):
1545*cda5da8dSAndroid Build Coastguard Worker            parser.CharacterDataHandler = target.data
1546*cda5da8dSAndroid Build Coastguard Worker        # miscellaneous callbacks
1547*cda5da8dSAndroid Build Coastguard Worker        if hasattr(target, 'comment'):
1548*cda5da8dSAndroid Build Coastguard Worker            parser.CommentHandler = target.comment
1549*cda5da8dSAndroid Build Coastguard Worker        if hasattr(target, 'pi'):
1550*cda5da8dSAndroid Build Coastguard Worker            parser.ProcessingInstructionHandler = target.pi
1551*cda5da8dSAndroid Build Coastguard Worker        # Configure pyexpat: buffering, new-style attribute handling.
1552*cda5da8dSAndroid Build Coastguard Worker        parser.buffer_text = 1
1553*cda5da8dSAndroid Build Coastguard Worker        parser.ordered_attributes = 1
1554*cda5da8dSAndroid Build Coastguard Worker        self._doctype = None
1555*cda5da8dSAndroid Build Coastguard Worker        self.entity = {}
1556*cda5da8dSAndroid Build Coastguard Worker        try:
1557*cda5da8dSAndroid Build Coastguard Worker            self.version = "Expat %d.%d.%d" % expat.version_info
1558*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
1559*cda5da8dSAndroid Build Coastguard Worker            pass # unknown
1560*cda5da8dSAndroid Build Coastguard Worker
1561*cda5da8dSAndroid Build Coastguard Worker    def _setevents(self, events_queue, events_to_report):
1562*cda5da8dSAndroid Build Coastguard Worker        # Internal API for XMLPullParser
1563*cda5da8dSAndroid Build Coastguard Worker        # events_to_report: a list of events to report during parsing (same as
1564*cda5da8dSAndroid Build Coastguard Worker        # the *events* of XMLPullParser's constructor.
1565*cda5da8dSAndroid Build Coastguard Worker        # events_queue: a list of actual parsing events that will be populated
1566*cda5da8dSAndroid Build Coastguard Worker        # by the underlying parser.
1567*cda5da8dSAndroid Build Coastguard Worker        #
1568*cda5da8dSAndroid Build Coastguard Worker        parser = self._parser
1569*cda5da8dSAndroid Build Coastguard Worker        append = events_queue.append
1570*cda5da8dSAndroid Build Coastguard Worker        for event_name in events_to_report:
1571*cda5da8dSAndroid Build Coastguard Worker            if event_name == "start":
1572*cda5da8dSAndroid Build Coastguard Worker                parser.ordered_attributes = 1
1573*cda5da8dSAndroid Build Coastguard Worker                def handler(tag, attrib_in, event=event_name, append=append,
1574*cda5da8dSAndroid Build Coastguard Worker                            start=self._start):
1575*cda5da8dSAndroid Build Coastguard Worker                    append((event, start(tag, attrib_in)))
1576*cda5da8dSAndroid Build Coastguard Worker                parser.StartElementHandler = handler
1577*cda5da8dSAndroid Build Coastguard Worker            elif event_name == "end":
1578*cda5da8dSAndroid Build Coastguard Worker                def handler(tag, event=event_name, append=append,
1579*cda5da8dSAndroid Build Coastguard Worker                            end=self._end):
1580*cda5da8dSAndroid Build Coastguard Worker                    append((event, end(tag)))
1581*cda5da8dSAndroid Build Coastguard Worker                parser.EndElementHandler = handler
1582*cda5da8dSAndroid Build Coastguard Worker            elif event_name == "start-ns":
1583*cda5da8dSAndroid Build Coastguard Worker                # TreeBuilder does not implement .start_ns()
1584*cda5da8dSAndroid Build Coastguard Worker                if hasattr(self.target, "start_ns"):
1585*cda5da8dSAndroid Build Coastguard Worker                    def handler(prefix, uri, event=event_name, append=append,
1586*cda5da8dSAndroid Build Coastguard Worker                                start_ns=self._start_ns):
1587*cda5da8dSAndroid Build Coastguard Worker                        append((event, start_ns(prefix, uri)))
1588*cda5da8dSAndroid Build Coastguard Worker                else:
1589*cda5da8dSAndroid Build Coastguard Worker                    def handler(prefix, uri, event=event_name, append=append):
1590*cda5da8dSAndroid Build Coastguard Worker                        append((event, (prefix or '', uri or '')))
1591*cda5da8dSAndroid Build Coastguard Worker                parser.StartNamespaceDeclHandler = handler
1592*cda5da8dSAndroid Build Coastguard Worker            elif event_name == "end-ns":
1593*cda5da8dSAndroid Build Coastguard Worker                # TreeBuilder does not implement .end_ns()
1594*cda5da8dSAndroid Build Coastguard Worker                if hasattr(self.target, "end_ns"):
1595*cda5da8dSAndroid Build Coastguard Worker                    def handler(prefix, event=event_name, append=append,
1596*cda5da8dSAndroid Build Coastguard Worker                                end_ns=self._end_ns):
1597*cda5da8dSAndroid Build Coastguard Worker                        append((event, end_ns(prefix)))
1598*cda5da8dSAndroid Build Coastguard Worker                else:
1599*cda5da8dSAndroid Build Coastguard Worker                    def handler(prefix, event=event_name, append=append):
1600*cda5da8dSAndroid Build Coastguard Worker                        append((event, None))
1601*cda5da8dSAndroid Build Coastguard Worker                parser.EndNamespaceDeclHandler = handler
1602*cda5da8dSAndroid Build Coastguard Worker            elif event_name == 'comment':
1603*cda5da8dSAndroid Build Coastguard Worker                def handler(text, event=event_name, append=append, self=self):
1604*cda5da8dSAndroid Build Coastguard Worker                    append((event, self.target.comment(text)))
1605*cda5da8dSAndroid Build Coastguard Worker                parser.CommentHandler = handler
1606*cda5da8dSAndroid Build Coastguard Worker            elif event_name == 'pi':
1607*cda5da8dSAndroid Build Coastguard Worker                def handler(pi_target, data, event=event_name, append=append,
1608*cda5da8dSAndroid Build Coastguard Worker                            self=self):
1609*cda5da8dSAndroid Build Coastguard Worker                    append((event, self.target.pi(pi_target, data)))
1610*cda5da8dSAndroid Build Coastguard Worker                parser.ProcessingInstructionHandler = handler
1611*cda5da8dSAndroid Build Coastguard Worker            else:
1612*cda5da8dSAndroid Build Coastguard Worker                raise ValueError("unknown event %r" % event_name)
1613*cda5da8dSAndroid Build Coastguard Worker
1614*cda5da8dSAndroid Build Coastguard Worker    def _raiseerror(self, value):
1615*cda5da8dSAndroid Build Coastguard Worker        err = ParseError(value)
1616*cda5da8dSAndroid Build Coastguard Worker        err.code = value.code
1617*cda5da8dSAndroid Build Coastguard Worker        err.position = value.lineno, value.offset
1618*cda5da8dSAndroid Build Coastguard Worker        raise err
1619*cda5da8dSAndroid Build Coastguard Worker
1620*cda5da8dSAndroid Build Coastguard Worker    def _fixname(self, key):
1621*cda5da8dSAndroid Build Coastguard Worker        # expand qname, and convert name string to ascii, if possible
1622*cda5da8dSAndroid Build Coastguard Worker        try:
1623*cda5da8dSAndroid Build Coastguard Worker            name = self._names[key]
1624*cda5da8dSAndroid Build Coastguard Worker        except KeyError:
1625*cda5da8dSAndroid Build Coastguard Worker            name = key
1626*cda5da8dSAndroid Build Coastguard Worker            if "}" in name:
1627*cda5da8dSAndroid Build Coastguard Worker                name = "{" + name
1628*cda5da8dSAndroid Build Coastguard Worker            self._names[key] = name
1629*cda5da8dSAndroid Build Coastguard Worker        return name
1630*cda5da8dSAndroid Build Coastguard Worker
1631*cda5da8dSAndroid Build Coastguard Worker    def _start_ns(self, prefix, uri):
1632*cda5da8dSAndroid Build Coastguard Worker        return self.target.start_ns(prefix or '', uri or '')
1633*cda5da8dSAndroid Build Coastguard Worker
1634*cda5da8dSAndroid Build Coastguard Worker    def _end_ns(self, prefix):
1635*cda5da8dSAndroid Build Coastguard Worker        return self.target.end_ns(prefix or '')
1636*cda5da8dSAndroid Build Coastguard Worker
1637*cda5da8dSAndroid Build Coastguard Worker    def _start(self, tag, attr_list):
1638*cda5da8dSAndroid Build Coastguard Worker        # Handler for expat's StartElementHandler. Since ordered_attributes
1639*cda5da8dSAndroid Build Coastguard Worker        # is set, the attributes are reported as a list of alternating
1640*cda5da8dSAndroid Build Coastguard Worker        # attribute name,value.
1641*cda5da8dSAndroid Build Coastguard Worker        fixname = self._fixname
1642*cda5da8dSAndroid Build Coastguard Worker        tag = fixname(tag)
1643*cda5da8dSAndroid Build Coastguard Worker        attrib = {}
1644*cda5da8dSAndroid Build Coastguard Worker        if attr_list:
1645*cda5da8dSAndroid Build Coastguard Worker            for i in range(0, len(attr_list), 2):
1646*cda5da8dSAndroid Build Coastguard Worker                attrib[fixname(attr_list[i])] = attr_list[i+1]
1647*cda5da8dSAndroid Build Coastguard Worker        return self.target.start(tag, attrib)
1648*cda5da8dSAndroid Build Coastguard Worker
1649*cda5da8dSAndroid Build Coastguard Worker    def _end(self, tag):
1650*cda5da8dSAndroid Build Coastguard Worker        return self.target.end(self._fixname(tag))
1651*cda5da8dSAndroid Build Coastguard Worker
1652*cda5da8dSAndroid Build Coastguard Worker    def _default(self, text):
1653*cda5da8dSAndroid Build Coastguard Worker        prefix = text[:1]
1654*cda5da8dSAndroid Build Coastguard Worker        if prefix == "&":
1655*cda5da8dSAndroid Build Coastguard Worker            # deal with undefined entities
1656*cda5da8dSAndroid Build Coastguard Worker            try:
1657*cda5da8dSAndroid Build Coastguard Worker                data_handler = self.target.data
1658*cda5da8dSAndroid Build Coastguard Worker            except AttributeError:
1659*cda5da8dSAndroid Build Coastguard Worker                return
1660*cda5da8dSAndroid Build Coastguard Worker            try:
1661*cda5da8dSAndroid Build Coastguard Worker                data_handler(self.entity[text[1:-1]])
1662*cda5da8dSAndroid Build Coastguard Worker            except KeyError:
1663*cda5da8dSAndroid Build Coastguard Worker                from xml.parsers import expat
1664*cda5da8dSAndroid Build Coastguard Worker                err = expat.error(
1665*cda5da8dSAndroid Build Coastguard Worker                    "undefined entity %s: line %d, column %d" %
1666*cda5da8dSAndroid Build Coastguard Worker                    (text, self.parser.ErrorLineNumber,
1667*cda5da8dSAndroid Build Coastguard Worker                    self.parser.ErrorColumnNumber)
1668*cda5da8dSAndroid Build Coastguard Worker                    )
1669*cda5da8dSAndroid Build Coastguard Worker                err.code = 11 # XML_ERROR_UNDEFINED_ENTITY
1670*cda5da8dSAndroid Build Coastguard Worker                err.lineno = self.parser.ErrorLineNumber
1671*cda5da8dSAndroid Build Coastguard Worker                err.offset = self.parser.ErrorColumnNumber
1672*cda5da8dSAndroid Build Coastguard Worker                raise err
1673*cda5da8dSAndroid Build Coastguard Worker        elif prefix == "<" and text[:9] == "<!DOCTYPE":
1674*cda5da8dSAndroid Build Coastguard Worker            self._doctype = [] # inside a doctype declaration
1675*cda5da8dSAndroid Build Coastguard Worker        elif self._doctype is not None:
1676*cda5da8dSAndroid Build Coastguard Worker            # parse doctype contents
1677*cda5da8dSAndroid Build Coastguard Worker            if prefix == ">":
1678*cda5da8dSAndroid Build Coastguard Worker                self._doctype = None
1679*cda5da8dSAndroid Build Coastguard Worker                return
1680*cda5da8dSAndroid Build Coastguard Worker            text = text.strip()
1681*cda5da8dSAndroid Build Coastguard Worker            if not text:
1682*cda5da8dSAndroid Build Coastguard Worker                return
1683*cda5da8dSAndroid Build Coastguard Worker            self._doctype.append(text)
1684*cda5da8dSAndroid Build Coastguard Worker            n = len(self._doctype)
1685*cda5da8dSAndroid Build Coastguard Worker            if n > 2:
1686*cda5da8dSAndroid Build Coastguard Worker                type = self._doctype[1]
1687*cda5da8dSAndroid Build Coastguard Worker                if type == "PUBLIC" and n == 4:
1688*cda5da8dSAndroid Build Coastguard Worker                    name, type, pubid, system = self._doctype
1689*cda5da8dSAndroid Build Coastguard Worker                    if pubid:
1690*cda5da8dSAndroid Build Coastguard Worker                        pubid = pubid[1:-1]
1691*cda5da8dSAndroid Build Coastguard Worker                elif type == "SYSTEM" and n == 3:
1692*cda5da8dSAndroid Build Coastguard Worker                    name, type, system = self._doctype
1693*cda5da8dSAndroid Build Coastguard Worker                    pubid = None
1694*cda5da8dSAndroid Build Coastguard Worker                else:
1695*cda5da8dSAndroid Build Coastguard Worker                    return
1696*cda5da8dSAndroid Build Coastguard Worker                if hasattr(self.target, "doctype"):
1697*cda5da8dSAndroid Build Coastguard Worker                    self.target.doctype(name, pubid, system[1:-1])
1698*cda5da8dSAndroid Build Coastguard Worker                elif hasattr(self, "doctype"):
1699*cda5da8dSAndroid Build Coastguard Worker                    warnings.warn(
1700*cda5da8dSAndroid Build Coastguard Worker                        "The doctype() method of XMLParser is ignored.  "
1701*cda5da8dSAndroid Build Coastguard Worker                        "Define doctype() method on the TreeBuilder target.",
1702*cda5da8dSAndroid Build Coastguard Worker                        RuntimeWarning)
1703*cda5da8dSAndroid Build Coastguard Worker
1704*cda5da8dSAndroid Build Coastguard Worker                self._doctype = None
1705*cda5da8dSAndroid Build Coastguard Worker
1706*cda5da8dSAndroid Build Coastguard Worker    def feed(self, data):
1707*cda5da8dSAndroid Build Coastguard Worker        """Feed encoded data to parser."""
1708*cda5da8dSAndroid Build Coastguard Worker        try:
1709*cda5da8dSAndroid Build Coastguard Worker            self.parser.Parse(data, False)
1710*cda5da8dSAndroid Build Coastguard Worker        except self._error as v:
1711*cda5da8dSAndroid Build Coastguard Worker            self._raiseerror(v)
1712*cda5da8dSAndroid Build Coastguard Worker
1713*cda5da8dSAndroid Build Coastguard Worker    def close(self):
1714*cda5da8dSAndroid Build Coastguard Worker        """Finish feeding data to parser and return element structure."""
1715*cda5da8dSAndroid Build Coastguard Worker        try:
1716*cda5da8dSAndroid Build Coastguard Worker            self.parser.Parse(b"", True) # end of data
1717*cda5da8dSAndroid Build Coastguard Worker        except self._error as v:
1718*cda5da8dSAndroid Build Coastguard Worker            self._raiseerror(v)
1719*cda5da8dSAndroid Build Coastguard Worker        try:
1720*cda5da8dSAndroid Build Coastguard Worker            close_handler = self.target.close
1721*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
1722*cda5da8dSAndroid Build Coastguard Worker            pass
1723*cda5da8dSAndroid Build Coastguard Worker        else:
1724*cda5da8dSAndroid Build Coastguard Worker            return close_handler()
1725*cda5da8dSAndroid Build Coastguard Worker        finally:
1726*cda5da8dSAndroid Build Coastguard Worker            # get rid of circular references
1727*cda5da8dSAndroid Build Coastguard Worker            del self.parser, self._parser
1728*cda5da8dSAndroid Build Coastguard Worker            del self.target, self._target
1729*cda5da8dSAndroid Build Coastguard Worker
1730*cda5da8dSAndroid Build Coastguard Worker
1731*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
1732*cda5da8dSAndroid Build Coastguard Worker# C14N 2.0
1733*cda5da8dSAndroid Build Coastguard Worker
1734*cda5da8dSAndroid Build Coastguard Workerdef canonicalize(xml_data=None, *, out=None, from_file=None, **options):
1735*cda5da8dSAndroid Build Coastguard Worker    """Convert XML to its C14N 2.0 serialised form.
1736*cda5da8dSAndroid Build Coastguard Worker
1737*cda5da8dSAndroid Build Coastguard Worker    If *out* is provided, it must be a file or file-like object that receives
1738*cda5da8dSAndroid Build Coastguard Worker    the serialised canonical XML output (text, not bytes) through its ``.write()``
1739*cda5da8dSAndroid Build Coastguard Worker    method.  To write to a file, open it in text mode with encoding "utf-8".
1740*cda5da8dSAndroid Build Coastguard Worker    If *out* is not provided, this function returns the output as text string.
1741*cda5da8dSAndroid Build Coastguard Worker
1742*cda5da8dSAndroid Build Coastguard Worker    Either *xml_data* (an XML string) or *from_file* (a file path or
1743*cda5da8dSAndroid Build Coastguard Worker    file-like object) must be provided as input.
1744*cda5da8dSAndroid Build Coastguard Worker
1745*cda5da8dSAndroid Build Coastguard Worker    The configuration options are the same as for the ``C14NWriterTarget``.
1746*cda5da8dSAndroid Build Coastguard Worker    """
1747*cda5da8dSAndroid Build Coastguard Worker    if xml_data is None and from_file is None:
1748*cda5da8dSAndroid Build Coastguard Worker        raise ValueError("Either 'xml_data' or 'from_file' must be provided as input")
1749*cda5da8dSAndroid Build Coastguard Worker    sio = None
1750*cda5da8dSAndroid Build Coastguard Worker    if out is None:
1751*cda5da8dSAndroid Build Coastguard Worker        sio = out = io.StringIO()
1752*cda5da8dSAndroid Build Coastguard Worker
1753*cda5da8dSAndroid Build Coastguard Worker    parser = XMLParser(target=C14NWriterTarget(out.write, **options))
1754*cda5da8dSAndroid Build Coastguard Worker
1755*cda5da8dSAndroid Build Coastguard Worker    if xml_data is not None:
1756*cda5da8dSAndroid Build Coastguard Worker        parser.feed(xml_data)
1757*cda5da8dSAndroid Build Coastguard Worker        parser.close()
1758*cda5da8dSAndroid Build Coastguard Worker    elif from_file is not None:
1759*cda5da8dSAndroid Build Coastguard Worker        parse(from_file, parser=parser)
1760*cda5da8dSAndroid Build Coastguard Worker
1761*cda5da8dSAndroid Build Coastguard Worker    return sio.getvalue() if sio is not None else None
1762*cda5da8dSAndroid Build Coastguard Worker
1763*cda5da8dSAndroid Build Coastguard Worker
1764*cda5da8dSAndroid Build Coastguard Worker_looks_like_prefix_name = re.compile(r'^\w+:\w+$', re.UNICODE).match
1765*cda5da8dSAndroid Build Coastguard Worker
1766*cda5da8dSAndroid Build Coastguard Worker
1767*cda5da8dSAndroid Build Coastguard Workerclass C14NWriterTarget:
1768*cda5da8dSAndroid Build Coastguard Worker    """
1769*cda5da8dSAndroid Build Coastguard Worker    Canonicalization writer target for the XMLParser.
1770*cda5da8dSAndroid Build Coastguard Worker
1771*cda5da8dSAndroid Build Coastguard Worker    Serialises parse events to XML C14N 2.0.
1772*cda5da8dSAndroid Build Coastguard Worker
1773*cda5da8dSAndroid Build Coastguard Worker    The *write* function is used for writing out the resulting data stream
1774*cda5da8dSAndroid Build Coastguard Worker    as text (not bytes).  To write to a file, open it in text mode with encoding
1775*cda5da8dSAndroid Build Coastguard Worker    "utf-8" and pass its ``.write`` method.
1776*cda5da8dSAndroid Build Coastguard Worker
1777*cda5da8dSAndroid Build Coastguard Worker    Configuration options:
1778*cda5da8dSAndroid Build Coastguard Worker
1779*cda5da8dSAndroid Build Coastguard Worker    - *with_comments*: set to true to include comments
1780*cda5da8dSAndroid Build Coastguard Worker    - *strip_text*: set to true to strip whitespace before and after text content
1781*cda5da8dSAndroid Build Coastguard Worker    - *rewrite_prefixes*: set to true to replace namespace prefixes by "n{number}"
1782*cda5da8dSAndroid Build Coastguard Worker    - *qname_aware_tags*: a set of qname aware tag names in which prefixes
1783*cda5da8dSAndroid Build Coastguard Worker                          should be replaced in text content
1784*cda5da8dSAndroid Build Coastguard Worker    - *qname_aware_attrs*: a set of qname aware attribute names in which prefixes
1785*cda5da8dSAndroid Build Coastguard Worker                           should be replaced in text content
1786*cda5da8dSAndroid Build Coastguard Worker    - *exclude_attrs*: a set of attribute names that should not be serialised
1787*cda5da8dSAndroid Build Coastguard Worker    - *exclude_tags*: a set of tag names that should not be serialised
1788*cda5da8dSAndroid Build Coastguard Worker    """
1789*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, write, *,
1790*cda5da8dSAndroid Build Coastguard Worker                 with_comments=False, strip_text=False, rewrite_prefixes=False,
1791*cda5da8dSAndroid Build Coastguard Worker                 qname_aware_tags=None, qname_aware_attrs=None,
1792*cda5da8dSAndroid Build Coastguard Worker                 exclude_attrs=None, exclude_tags=None):
1793*cda5da8dSAndroid Build Coastguard Worker        self._write = write
1794*cda5da8dSAndroid Build Coastguard Worker        self._data = []
1795*cda5da8dSAndroid Build Coastguard Worker        self._with_comments = with_comments
1796*cda5da8dSAndroid Build Coastguard Worker        self._strip_text = strip_text
1797*cda5da8dSAndroid Build Coastguard Worker        self._exclude_attrs = set(exclude_attrs) if exclude_attrs else None
1798*cda5da8dSAndroid Build Coastguard Worker        self._exclude_tags = set(exclude_tags) if exclude_tags else None
1799*cda5da8dSAndroid Build Coastguard Worker
1800*cda5da8dSAndroid Build Coastguard Worker        self._rewrite_prefixes = rewrite_prefixes
1801*cda5da8dSAndroid Build Coastguard Worker        if qname_aware_tags:
1802*cda5da8dSAndroid Build Coastguard Worker            self._qname_aware_tags = set(qname_aware_tags)
1803*cda5da8dSAndroid Build Coastguard Worker        else:
1804*cda5da8dSAndroid Build Coastguard Worker            self._qname_aware_tags = None
1805*cda5da8dSAndroid Build Coastguard Worker        if qname_aware_attrs:
1806*cda5da8dSAndroid Build Coastguard Worker            self._find_qname_aware_attrs = set(qname_aware_attrs).intersection
1807*cda5da8dSAndroid Build Coastguard Worker        else:
1808*cda5da8dSAndroid Build Coastguard Worker            self._find_qname_aware_attrs = None
1809*cda5da8dSAndroid Build Coastguard Worker
1810*cda5da8dSAndroid Build Coastguard Worker        # Stack with globally and newly declared namespaces as (uri, prefix) pairs.
1811*cda5da8dSAndroid Build Coastguard Worker        self._declared_ns_stack = [[
1812*cda5da8dSAndroid Build Coastguard Worker            ("http://www.w3.org/XML/1998/namespace", "xml"),
1813*cda5da8dSAndroid Build Coastguard Worker        ]]
1814*cda5da8dSAndroid Build Coastguard Worker        # Stack with user declared namespace prefixes as (uri, prefix) pairs.
1815*cda5da8dSAndroid Build Coastguard Worker        self._ns_stack = []
1816*cda5da8dSAndroid Build Coastguard Worker        if not rewrite_prefixes:
1817*cda5da8dSAndroid Build Coastguard Worker            self._ns_stack.append(list(_namespace_map.items()))
1818*cda5da8dSAndroid Build Coastguard Worker        self._ns_stack.append([])
1819*cda5da8dSAndroid Build Coastguard Worker        self._prefix_map = {}
1820*cda5da8dSAndroid Build Coastguard Worker        self._preserve_space = [False]
1821*cda5da8dSAndroid Build Coastguard Worker        self._pending_start = None
1822*cda5da8dSAndroid Build Coastguard Worker        self._root_seen = False
1823*cda5da8dSAndroid Build Coastguard Worker        self._root_done = False
1824*cda5da8dSAndroid Build Coastguard Worker        self._ignored_depth = 0
1825*cda5da8dSAndroid Build Coastguard Worker
1826*cda5da8dSAndroid Build Coastguard Worker    def _iter_namespaces(self, ns_stack, _reversed=reversed):
1827*cda5da8dSAndroid Build Coastguard Worker        for namespaces in _reversed(ns_stack):
1828*cda5da8dSAndroid Build Coastguard Worker            if namespaces:  # almost no element declares new namespaces
1829*cda5da8dSAndroid Build Coastguard Worker                yield from namespaces
1830*cda5da8dSAndroid Build Coastguard Worker
1831*cda5da8dSAndroid Build Coastguard Worker    def _resolve_prefix_name(self, prefixed_name):
1832*cda5da8dSAndroid Build Coastguard Worker        prefix, name = prefixed_name.split(':', 1)
1833*cda5da8dSAndroid Build Coastguard Worker        for uri, p in self._iter_namespaces(self._ns_stack):
1834*cda5da8dSAndroid Build Coastguard Worker            if p == prefix:
1835*cda5da8dSAndroid Build Coastguard Worker                return f'{{{uri}}}{name}'
1836*cda5da8dSAndroid Build Coastguard Worker        raise ValueError(f'Prefix {prefix} of QName "{prefixed_name}" is not declared in scope')
1837*cda5da8dSAndroid Build Coastguard Worker
1838*cda5da8dSAndroid Build Coastguard Worker    def _qname(self, qname, uri=None):
1839*cda5da8dSAndroid Build Coastguard Worker        if uri is None:
1840*cda5da8dSAndroid Build Coastguard Worker            uri, tag = qname[1:].rsplit('}', 1) if qname[:1] == '{' else ('', qname)
1841*cda5da8dSAndroid Build Coastguard Worker        else:
1842*cda5da8dSAndroid Build Coastguard Worker            tag = qname
1843*cda5da8dSAndroid Build Coastguard Worker
1844*cda5da8dSAndroid Build Coastguard Worker        prefixes_seen = set()
1845*cda5da8dSAndroid Build Coastguard Worker        for u, prefix in self._iter_namespaces(self._declared_ns_stack):
1846*cda5da8dSAndroid Build Coastguard Worker            if u == uri and prefix not in prefixes_seen:
1847*cda5da8dSAndroid Build Coastguard Worker                return f'{prefix}:{tag}' if prefix else tag, tag, uri
1848*cda5da8dSAndroid Build Coastguard Worker            prefixes_seen.add(prefix)
1849*cda5da8dSAndroid Build Coastguard Worker
1850*cda5da8dSAndroid Build Coastguard Worker        # Not declared yet => add new declaration.
1851*cda5da8dSAndroid Build Coastguard Worker        if self._rewrite_prefixes:
1852*cda5da8dSAndroid Build Coastguard Worker            if uri in self._prefix_map:
1853*cda5da8dSAndroid Build Coastguard Worker                prefix = self._prefix_map[uri]
1854*cda5da8dSAndroid Build Coastguard Worker            else:
1855*cda5da8dSAndroid Build Coastguard Worker                prefix = self._prefix_map[uri] = f'n{len(self._prefix_map)}'
1856*cda5da8dSAndroid Build Coastguard Worker            self._declared_ns_stack[-1].append((uri, prefix))
1857*cda5da8dSAndroid Build Coastguard Worker            return f'{prefix}:{tag}', tag, uri
1858*cda5da8dSAndroid Build Coastguard Worker
1859*cda5da8dSAndroid Build Coastguard Worker        if not uri and '' not in prefixes_seen:
1860*cda5da8dSAndroid Build Coastguard Worker            # No default namespace declared => no prefix needed.
1861*cda5da8dSAndroid Build Coastguard Worker            return tag, tag, uri
1862*cda5da8dSAndroid Build Coastguard Worker
1863*cda5da8dSAndroid Build Coastguard Worker        for u, prefix in self._iter_namespaces(self._ns_stack):
1864*cda5da8dSAndroid Build Coastguard Worker            if u == uri:
1865*cda5da8dSAndroid Build Coastguard Worker                self._declared_ns_stack[-1].append((uri, prefix))
1866*cda5da8dSAndroid Build Coastguard Worker                return f'{prefix}:{tag}' if prefix else tag, tag, uri
1867*cda5da8dSAndroid Build Coastguard Worker
1868*cda5da8dSAndroid Build Coastguard Worker        if not uri:
1869*cda5da8dSAndroid Build Coastguard Worker            # As soon as a default namespace is defined,
1870*cda5da8dSAndroid Build Coastguard Worker            # anything that has no namespace (and thus, no prefix) goes there.
1871*cda5da8dSAndroid Build Coastguard Worker            return tag, tag, uri
1872*cda5da8dSAndroid Build Coastguard Worker
1873*cda5da8dSAndroid Build Coastguard Worker        raise ValueError(f'Namespace "{uri}" is not declared in scope')
1874*cda5da8dSAndroid Build Coastguard Worker
1875*cda5da8dSAndroid Build Coastguard Worker    def data(self, data):
1876*cda5da8dSAndroid Build Coastguard Worker        if not self._ignored_depth:
1877*cda5da8dSAndroid Build Coastguard Worker            self._data.append(data)
1878*cda5da8dSAndroid Build Coastguard Worker
1879*cda5da8dSAndroid Build Coastguard Worker    def _flush(self, _join_text=''.join):
1880*cda5da8dSAndroid Build Coastguard Worker        data = _join_text(self._data)
1881*cda5da8dSAndroid Build Coastguard Worker        del self._data[:]
1882*cda5da8dSAndroid Build Coastguard Worker        if self._strip_text and not self._preserve_space[-1]:
1883*cda5da8dSAndroid Build Coastguard Worker            data = data.strip()
1884*cda5da8dSAndroid Build Coastguard Worker        if self._pending_start is not None:
1885*cda5da8dSAndroid Build Coastguard Worker            args, self._pending_start = self._pending_start, None
1886*cda5da8dSAndroid Build Coastguard Worker            qname_text = data if data and _looks_like_prefix_name(data) else None
1887*cda5da8dSAndroid Build Coastguard Worker            self._start(*args, qname_text)
1888*cda5da8dSAndroid Build Coastguard Worker            if qname_text is not None:
1889*cda5da8dSAndroid Build Coastguard Worker                return
1890*cda5da8dSAndroid Build Coastguard Worker        if data and self._root_seen:
1891*cda5da8dSAndroid Build Coastguard Worker            self._write(_escape_cdata_c14n(data))
1892*cda5da8dSAndroid Build Coastguard Worker
1893*cda5da8dSAndroid Build Coastguard Worker    def start_ns(self, prefix, uri):
1894*cda5da8dSAndroid Build Coastguard Worker        if self._ignored_depth:
1895*cda5da8dSAndroid Build Coastguard Worker            return
1896*cda5da8dSAndroid Build Coastguard Worker        # we may have to resolve qnames in text content
1897*cda5da8dSAndroid Build Coastguard Worker        if self._data:
1898*cda5da8dSAndroid Build Coastguard Worker            self._flush()
1899*cda5da8dSAndroid Build Coastguard Worker        self._ns_stack[-1].append((uri, prefix))
1900*cda5da8dSAndroid Build Coastguard Worker
1901*cda5da8dSAndroid Build Coastguard Worker    def start(self, tag, attrs):
1902*cda5da8dSAndroid Build Coastguard Worker        if self._exclude_tags is not None and (
1903*cda5da8dSAndroid Build Coastguard Worker                self._ignored_depth or tag in self._exclude_tags):
1904*cda5da8dSAndroid Build Coastguard Worker            self._ignored_depth += 1
1905*cda5da8dSAndroid Build Coastguard Worker            return
1906*cda5da8dSAndroid Build Coastguard Worker        if self._data:
1907*cda5da8dSAndroid Build Coastguard Worker            self._flush()
1908*cda5da8dSAndroid Build Coastguard Worker
1909*cda5da8dSAndroid Build Coastguard Worker        new_namespaces = []
1910*cda5da8dSAndroid Build Coastguard Worker        self._declared_ns_stack.append(new_namespaces)
1911*cda5da8dSAndroid Build Coastguard Worker
1912*cda5da8dSAndroid Build Coastguard Worker        if self._qname_aware_tags is not None and tag in self._qname_aware_tags:
1913*cda5da8dSAndroid Build Coastguard Worker            # Need to parse text first to see if it requires a prefix declaration.
1914*cda5da8dSAndroid Build Coastguard Worker            self._pending_start = (tag, attrs, new_namespaces)
1915*cda5da8dSAndroid Build Coastguard Worker            return
1916*cda5da8dSAndroid Build Coastguard Worker        self._start(tag, attrs, new_namespaces)
1917*cda5da8dSAndroid Build Coastguard Worker
1918*cda5da8dSAndroid Build Coastguard Worker    def _start(self, tag, attrs, new_namespaces, qname_text=None):
1919*cda5da8dSAndroid Build Coastguard Worker        if self._exclude_attrs is not None and attrs:
1920*cda5da8dSAndroid Build Coastguard Worker            attrs = {k: v for k, v in attrs.items() if k not in self._exclude_attrs}
1921*cda5da8dSAndroid Build Coastguard Worker
1922*cda5da8dSAndroid Build Coastguard Worker        qnames = {tag, *attrs}
1923*cda5da8dSAndroid Build Coastguard Worker        resolved_names = {}
1924*cda5da8dSAndroid Build Coastguard Worker
1925*cda5da8dSAndroid Build Coastguard Worker        # Resolve prefixes in attribute and tag text.
1926*cda5da8dSAndroid Build Coastguard Worker        if qname_text is not None:
1927*cda5da8dSAndroid Build Coastguard Worker            qname = resolved_names[qname_text] = self._resolve_prefix_name(qname_text)
1928*cda5da8dSAndroid Build Coastguard Worker            qnames.add(qname)
1929*cda5da8dSAndroid Build Coastguard Worker        if self._find_qname_aware_attrs is not None and attrs:
1930*cda5da8dSAndroid Build Coastguard Worker            qattrs = self._find_qname_aware_attrs(attrs)
1931*cda5da8dSAndroid Build Coastguard Worker            if qattrs:
1932*cda5da8dSAndroid Build Coastguard Worker                for attr_name in qattrs:
1933*cda5da8dSAndroid Build Coastguard Worker                    value = attrs[attr_name]
1934*cda5da8dSAndroid Build Coastguard Worker                    if _looks_like_prefix_name(value):
1935*cda5da8dSAndroid Build Coastguard Worker                        qname = resolved_names[value] = self._resolve_prefix_name(value)
1936*cda5da8dSAndroid Build Coastguard Worker                        qnames.add(qname)
1937*cda5da8dSAndroid Build Coastguard Worker            else:
1938*cda5da8dSAndroid Build Coastguard Worker                qattrs = None
1939*cda5da8dSAndroid Build Coastguard Worker        else:
1940*cda5da8dSAndroid Build Coastguard Worker            qattrs = None
1941*cda5da8dSAndroid Build Coastguard Worker
1942*cda5da8dSAndroid Build Coastguard Worker        # Assign prefixes in lexicographical order of used URIs.
1943*cda5da8dSAndroid Build Coastguard Worker        parse_qname = self._qname
1944*cda5da8dSAndroid Build Coastguard Worker        parsed_qnames = {n: parse_qname(n) for n in sorted(
1945*cda5da8dSAndroid Build Coastguard Worker            qnames, key=lambda n: n.split('}', 1))}
1946*cda5da8dSAndroid Build Coastguard Worker
1947*cda5da8dSAndroid Build Coastguard Worker        # Write namespace declarations in prefix order ...
1948*cda5da8dSAndroid Build Coastguard Worker        if new_namespaces:
1949*cda5da8dSAndroid Build Coastguard Worker            attr_list = [
1950*cda5da8dSAndroid Build Coastguard Worker                ('xmlns:' + prefix if prefix else 'xmlns', uri)
1951*cda5da8dSAndroid Build Coastguard Worker                for uri, prefix in new_namespaces
1952*cda5da8dSAndroid Build Coastguard Worker            ]
1953*cda5da8dSAndroid Build Coastguard Worker            attr_list.sort()
1954*cda5da8dSAndroid Build Coastguard Worker        else:
1955*cda5da8dSAndroid Build Coastguard Worker            # almost always empty
1956*cda5da8dSAndroid Build Coastguard Worker            attr_list = []
1957*cda5da8dSAndroid Build Coastguard Worker
1958*cda5da8dSAndroid Build Coastguard Worker        # ... followed by attributes in URI+name order
1959*cda5da8dSAndroid Build Coastguard Worker        if attrs:
1960*cda5da8dSAndroid Build Coastguard Worker            for k, v in sorted(attrs.items()):
1961*cda5da8dSAndroid Build Coastguard Worker                if qattrs is not None and k in qattrs and v in resolved_names:
1962*cda5da8dSAndroid Build Coastguard Worker                    v = parsed_qnames[resolved_names[v]][0]
1963*cda5da8dSAndroid Build Coastguard Worker                attr_qname, attr_name, uri = parsed_qnames[k]
1964*cda5da8dSAndroid Build Coastguard Worker                # No prefix for attributes in default ('') namespace.
1965*cda5da8dSAndroid Build Coastguard Worker                attr_list.append((attr_qname if uri else attr_name, v))
1966*cda5da8dSAndroid Build Coastguard Worker
1967*cda5da8dSAndroid Build Coastguard Worker        # Honour xml:space attributes.
1968*cda5da8dSAndroid Build Coastguard Worker        space_behaviour = attrs.get('{http://www.w3.org/XML/1998/namespace}space')
1969*cda5da8dSAndroid Build Coastguard Worker        self._preserve_space.append(
1970*cda5da8dSAndroid Build Coastguard Worker            space_behaviour == 'preserve' if space_behaviour
1971*cda5da8dSAndroid Build Coastguard Worker            else self._preserve_space[-1])
1972*cda5da8dSAndroid Build Coastguard Worker
1973*cda5da8dSAndroid Build Coastguard Worker        # Write the tag.
1974*cda5da8dSAndroid Build Coastguard Worker        write = self._write
1975*cda5da8dSAndroid Build Coastguard Worker        write('<' + parsed_qnames[tag][0])
1976*cda5da8dSAndroid Build Coastguard Worker        if attr_list:
1977*cda5da8dSAndroid Build Coastguard Worker            write(''.join([f' {k}="{_escape_attrib_c14n(v)}"' for k, v in attr_list]))
1978*cda5da8dSAndroid Build Coastguard Worker        write('>')
1979*cda5da8dSAndroid Build Coastguard Worker
1980*cda5da8dSAndroid Build Coastguard Worker        # Write the resolved qname text content.
1981*cda5da8dSAndroid Build Coastguard Worker        if qname_text is not None:
1982*cda5da8dSAndroid Build Coastguard Worker            write(_escape_cdata_c14n(parsed_qnames[resolved_names[qname_text]][0]))
1983*cda5da8dSAndroid Build Coastguard Worker
1984*cda5da8dSAndroid Build Coastguard Worker        self._root_seen = True
1985*cda5da8dSAndroid Build Coastguard Worker        self._ns_stack.append([])
1986*cda5da8dSAndroid Build Coastguard Worker
1987*cda5da8dSAndroid Build Coastguard Worker    def end(self, tag):
1988*cda5da8dSAndroid Build Coastguard Worker        if self._ignored_depth:
1989*cda5da8dSAndroid Build Coastguard Worker            self._ignored_depth -= 1
1990*cda5da8dSAndroid Build Coastguard Worker            return
1991*cda5da8dSAndroid Build Coastguard Worker        if self._data:
1992*cda5da8dSAndroid Build Coastguard Worker            self._flush()
1993*cda5da8dSAndroid Build Coastguard Worker        self._write(f'</{self._qname(tag)[0]}>')
1994*cda5da8dSAndroid Build Coastguard Worker        self._preserve_space.pop()
1995*cda5da8dSAndroid Build Coastguard Worker        self._root_done = len(self._preserve_space) == 1
1996*cda5da8dSAndroid Build Coastguard Worker        self._declared_ns_stack.pop()
1997*cda5da8dSAndroid Build Coastguard Worker        self._ns_stack.pop()
1998*cda5da8dSAndroid Build Coastguard Worker
1999*cda5da8dSAndroid Build Coastguard Worker    def comment(self, text):
2000*cda5da8dSAndroid Build Coastguard Worker        if not self._with_comments:
2001*cda5da8dSAndroid Build Coastguard Worker            return
2002*cda5da8dSAndroid Build Coastguard Worker        if self._ignored_depth:
2003*cda5da8dSAndroid Build Coastguard Worker            return
2004*cda5da8dSAndroid Build Coastguard Worker        if self._root_done:
2005*cda5da8dSAndroid Build Coastguard Worker            self._write('\n')
2006*cda5da8dSAndroid Build Coastguard Worker        elif self._root_seen and self._data:
2007*cda5da8dSAndroid Build Coastguard Worker            self._flush()
2008*cda5da8dSAndroid Build Coastguard Worker        self._write(f'<!--{_escape_cdata_c14n(text)}-->')
2009*cda5da8dSAndroid Build Coastguard Worker        if not self._root_seen:
2010*cda5da8dSAndroid Build Coastguard Worker            self._write('\n')
2011*cda5da8dSAndroid Build Coastguard Worker
2012*cda5da8dSAndroid Build Coastguard Worker    def pi(self, target, data):
2013*cda5da8dSAndroid Build Coastguard Worker        if self._ignored_depth:
2014*cda5da8dSAndroid Build Coastguard Worker            return
2015*cda5da8dSAndroid Build Coastguard Worker        if self._root_done:
2016*cda5da8dSAndroid Build Coastguard Worker            self._write('\n')
2017*cda5da8dSAndroid Build Coastguard Worker        elif self._root_seen and self._data:
2018*cda5da8dSAndroid Build Coastguard Worker            self._flush()
2019*cda5da8dSAndroid Build Coastguard Worker        self._write(
2020*cda5da8dSAndroid Build Coastguard Worker            f'<?{target} {_escape_cdata_c14n(data)}?>' if data else f'<?{target}?>')
2021*cda5da8dSAndroid Build Coastguard Worker        if not self._root_seen:
2022*cda5da8dSAndroid Build Coastguard Worker            self._write('\n')
2023*cda5da8dSAndroid Build Coastguard Worker
2024*cda5da8dSAndroid Build Coastguard Worker
2025*cda5da8dSAndroid Build Coastguard Workerdef _escape_cdata_c14n(text):
2026*cda5da8dSAndroid Build Coastguard Worker    # escape character data
2027*cda5da8dSAndroid Build Coastguard Worker    try:
2028*cda5da8dSAndroid Build Coastguard Worker        # it's worth avoiding do-nothing calls for strings that are
2029*cda5da8dSAndroid Build Coastguard Worker        # shorter than 500 character, or so.  assume that's, by far,
2030*cda5da8dSAndroid Build Coastguard Worker        # the most common case in most applications.
2031*cda5da8dSAndroid Build Coastguard Worker        if '&' in text:
2032*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('&', '&amp;')
2033*cda5da8dSAndroid Build Coastguard Worker        if '<' in text:
2034*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('<', '&lt;')
2035*cda5da8dSAndroid Build Coastguard Worker        if '>' in text:
2036*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('>', '&gt;')
2037*cda5da8dSAndroid Build Coastguard Worker        if '\r' in text:
2038*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('\r', '&#xD;')
2039*cda5da8dSAndroid Build Coastguard Worker        return text
2040*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError):
2041*cda5da8dSAndroid Build Coastguard Worker        _raise_serialization_error(text)
2042*cda5da8dSAndroid Build Coastguard Worker
2043*cda5da8dSAndroid Build Coastguard Worker
2044*cda5da8dSAndroid Build Coastguard Workerdef _escape_attrib_c14n(text):
2045*cda5da8dSAndroid Build Coastguard Worker    # escape attribute value
2046*cda5da8dSAndroid Build Coastguard Worker    try:
2047*cda5da8dSAndroid Build Coastguard Worker        if '&' in text:
2048*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('&', '&amp;')
2049*cda5da8dSAndroid Build Coastguard Worker        if '<' in text:
2050*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('<', '&lt;')
2051*cda5da8dSAndroid Build Coastguard Worker        if '"' in text:
2052*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('"', '&quot;')
2053*cda5da8dSAndroid Build Coastguard Worker        if '\t' in text:
2054*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('\t', '&#x9;')
2055*cda5da8dSAndroid Build Coastguard Worker        if '\n' in text:
2056*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('\n', '&#xA;')
2057*cda5da8dSAndroid Build Coastguard Worker        if '\r' in text:
2058*cda5da8dSAndroid Build Coastguard Worker            text = text.replace('\r', '&#xD;')
2059*cda5da8dSAndroid Build Coastguard Worker        return text
2060*cda5da8dSAndroid Build Coastguard Worker    except (TypeError, AttributeError):
2061*cda5da8dSAndroid Build Coastguard Worker        _raise_serialization_error(text)
2062*cda5da8dSAndroid Build Coastguard Worker
2063*cda5da8dSAndroid Build Coastguard Worker
2064*cda5da8dSAndroid Build Coastguard Worker# --------------------------------------------------------------------
2065*cda5da8dSAndroid Build Coastguard Worker
2066*cda5da8dSAndroid Build Coastguard Worker# Import the C accelerators
2067*cda5da8dSAndroid Build Coastguard Workertry:
2068*cda5da8dSAndroid Build Coastguard Worker    # Element is going to be shadowed by the C implementation. We need to keep
2069*cda5da8dSAndroid Build Coastguard Worker    # the Python version of it accessible for some "creative" by external code
2070*cda5da8dSAndroid Build Coastguard Worker    # (see tests)
2071*cda5da8dSAndroid Build Coastguard Worker    _Element_Py = Element
2072*cda5da8dSAndroid Build Coastguard Worker
2073*cda5da8dSAndroid Build Coastguard Worker    # Element, SubElement, ParseError, TreeBuilder, XMLParser, _set_factories
2074*cda5da8dSAndroid Build Coastguard Worker    from _elementtree import *
2075*cda5da8dSAndroid Build Coastguard Worker    from _elementtree import _set_factories
2076*cda5da8dSAndroid Build Coastguard Workerexcept ImportError:
2077*cda5da8dSAndroid Build Coastguard Worker    pass
2078*cda5da8dSAndroid Build Coastguard Workerelse:
2079*cda5da8dSAndroid Build Coastguard Worker    _set_factories(Comment, ProcessingInstruction)
2080