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("&", "&") 1030*cda5da8dSAndroid Build Coastguard Worker if "<" in text: 1031*cda5da8dSAndroid Build Coastguard Worker text = text.replace("<", "<") 1032*cda5da8dSAndroid Build Coastguard Worker if ">" in text: 1033*cda5da8dSAndroid Build Coastguard Worker text = text.replace(">", ">") 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("&", "&") 1043*cda5da8dSAndroid Build Coastguard Worker if "<" in text: 1044*cda5da8dSAndroid Build Coastguard Worker text = text.replace("<", "<") 1045*cda5da8dSAndroid Build Coastguard Worker if ">" in text: 1046*cda5da8dSAndroid Build Coastguard Worker text = text.replace(">", ">") 1047*cda5da8dSAndroid Build Coastguard Worker if "\"" in text: 1048*cda5da8dSAndroid Build Coastguard Worker text = text.replace("\"", """) 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", " ") 1058*cda5da8dSAndroid Build Coastguard Worker if "\n" in text: 1059*cda5da8dSAndroid Build Coastguard Worker text = text.replace("\n", " ") 1060*cda5da8dSAndroid Build Coastguard Worker if "\t" in text: 1061*cda5da8dSAndroid Build Coastguard Worker text = text.replace("\t", "	") 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("&", "&") 1071*cda5da8dSAndroid Build Coastguard Worker if ">" in text: 1072*cda5da8dSAndroid Build Coastguard Worker text = text.replace(">", ">") 1073*cda5da8dSAndroid Build Coastguard Worker if "\"" in text: 1074*cda5da8dSAndroid Build Coastguard Worker text = text.replace("\"", """) 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('&', '&') 2033*cda5da8dSAndroid Build Coastguard Worker if '<' in text: 2034*cda5da8dSAndroid Build Coastguard Worker text = text.replace('<', '<') 2035*cda5da8dSAndroid Build Coastguard Worker if '>' in text: 2036*cda5da8dSAndroid Build Coastguard Worker text = text.replace('>', '>') 2037*cda5da8dSAndroid Build Coastguard Worker if '\r' in text: 2038*cda5da8dSAndroid Build Coastguard Worker text = text.replace('\r', '
') 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('&', '&') 2049*cda5da8dSAndroid Build Coastguard Worker if '<' in text: 2050*cda5da8dSAndroid Build Coastguard Worker text = text.replace('<', '<') 2051*cda5da8dSAndroid Build Coastguard Worker if '"' in text: 2052*cda5da8dSAndroid Build Coastguard Worker text = text.replace('"', '"') 2053*cda5da8dSAndroid Build Coastguard Worker if '\t' in text: 2054*cda5da8dSAndroid Build Coastguard Worker text = text.replace('\t', '	') 2055*cda5da8dSAndroid Build Coastguard Worker if '\n' in text: 2056*cda5da8dSAndroid Build Coastguard Worker text = text.replace('\n', '
') 2057*cda5da8dSAndroid Build Coastguard Worker if '\r' in text: 2058*cda5da8dSAndroid Build Coastguard Worker text = text.replace('\r', '
') 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