ElementTree.py 72 KB

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