ElementTree.py 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675
  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 http://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. "iselement", "iterparse",
  65. "parse", "ParseError",
  66. "PI", "ProcessingInstruction",
  67. "QName",
  68. "SubElement",
  69. "tostring", "tostringlist",
  70. "TreeBuilder",
  71. "VERSION",
  72. "XML", "XMLID",
  73. "XMLParser",
  74. "register_namespace",
  75. ]
  76. VERSION = "1.3.0"
  77. import sys
  78. import re
  79. import warnings
  80. import io
  81. import contextlib
  82. from . import ElementPath
  83. class ParseError(SyntaxError):
  84. """An error when parsing an XML document.
  85. In addition to its exception value, a ParseError contains
  86. two extra attributes:
  87. 'code' - the specific exception code
  88. 'position' - the line and column of the error
  89. """
  90. pass
  91. # --------------------------------------------------------------------
  92. def iselement(element):
  93. """Return True if *element* appears to be an Element."""
  94. return hasattr(element, 'tag')
  95. class Element:
  96. """An XML element.
  97. This class is the reference implementation of the Element interface.
  98. An element's length is its number of subelements. That means if you
  99. want to check if an element is truly empty, you should check BOTH
  100. its length AND its text attribute.
  101. The element tag, attribute names, and attribute values can be either
  102. bytes or strings.
  103. *tag* is the element name. *attrib* is an optional dictionary containing
  104. element attributes. *extra* are additional element attributes given as
  105. keyword arguments.
  106. Example form:
  107. <tag attrib>text<child/>...</tag>tail
  108. """
  109. tag = None
  110. """The element's name."""
  111. attrib = None
  112. """Dictionary of the element's attributes."""
  113. text = None
  114. """
  115. Text before first subelement. This is either a string or the value None.
  116. Note that if there is no text, this attribute may be either
  117. None or the empty string, depending on the parser.
  118. """
  119. tail = None
  120. """
  121. Text after this element's end tag, but before the next sibling element's
  122. start tag. This is either a string or the value None. Note that if there
  123. was no text, this attribute may be either None or an empty string,
  124. depending on the parser.
  125. """
  126. def __init__(self, tag, attrib={}, **extra):
  127. if not isinstance(attrib, dict):
  128. raise TypeError("attrib must be dict, not %s" % (
  129. attrib.__class__.__name__,))
  130. attrib = attrib.copy()
  131. attrib.update(extra)
  132. self.tag = tag
  133. self.attrib = attrib
  134. self._children = []
  135. def __repr__(self):
  136. return "<%s %r at %#x>" % (self.__class__.__name__, self.tag, id(self))
  137. def makeelement(self, tag, attrib):
  138. """Create a new element with the same type.
  139. *tag* is a string containing the element name.
  140. *attrib* is a dictionary containing the element attributes.
  141. Do not call this method, use the SubElement factory function instead.
  142. """
  143. return self.__class__(tag, attrib)
  144. def copy(self):
  145. """Return copy of current element.
  146. This creates a shallow copy. Subelements will be shared with the
  147. original tree.
  148. """
  149. elem = self.makeelement(self.tag, self.attrib)
  150. elem.text = self.text
  151. elem.tail = self.tail
  152. elem[:] = self
  153. return elem
  154. def __len__(self):
  155. return len(self._children)
  156. def __bool__(self):
  157. warnings.warn(
  158. "The behavior of this method will change in future versions. "
  159. "Use specific 'len(elem)' or 'elem is not None' test instead.",
  160. FutureWarning, stacklevel=2
  161. )
  162. return len(self._children) != 0 # emulate old behaviour, for now
  163. def __getitem__(self, index):
  164. return self._children[index]
  165. def __setitem__(self, index, element):
  166. # if isinstance(index, slice):
  167. # for elt in element:
  168. # assert iselement(elt)
  169. # else:
  170. # assert iselement(element)
  171. self._children[index] = element
  172. def __delitem__(self, index):
  173. del self._children[index]
  174. def append(self, subelement):
  175. """Add *subelement* to the end of this element.
  176. The new element will appear in document order after the last existing
  177. subelement (or directly after the text, if it's the first subelement),
  178. but before the end tag for this element.
  179. """
  180. self._assert_is_element(subelement)
  181. self._children.append(subelement)
  182. def extend(self, elements):
  183. """Append subelements from a sequence.
  184. *elements* is a sequence with zero or more elements.
  185. """
  186. for element in elements:
  187. self._assert_is_element(element)
  188. self._children.extend(elements)
  189. def insert(self, index, subelement):
  190. """Insert *subelement* at position *index*."""
  191. self._assert_is_element(subelement)
  192. self._children.insert(index, subelement)
  193. def _assert_is_element(self, e):
  194. # Need to refer to the actual Python implementation, not the
  195. # shadowing C implementation.
  196. if not isinstance(e, _Element_Py):
  197. raise TypeError('expected an Element, not %s' % type(e).__name__)
  198. def remove(self, subelement):
  199. """Remove matching subelement.
  200. Unlike the find methods, this method compares elements based on
  201. identity, NOT ON tag value or contents. To remove subelements by
  202. other means, the easiest way is to use a list comprehension to
  203. select what elements to keep, and then use slice assignment to update
  204. the parent element.
  205. ValueError is raised if a matching element could not be found.
  206. """
  207. # assert iselement(element)
  208. self._children.remove(subelement)
  209. def getchildren(self):
  210. """(Deprecated) Return all subelements.
  211. Elements are returned in document order.
  212. """
  213. warnings.warn(
  214. "This method will be removed in future versions. "
  215. "Use 'list(elem)' or iteration over elem instead.",
  216. DeprecationWarning, stacklevel=2
  217. )
  218. return self._children
  219. def find(self, path, namespaces=None):
  220. """Find first matching element by tag name or path.
  221. *path* is a string having either an element tag or an XPath,
  222. *namespaces* is an optional mapping from namespace prefix to full name.
  223. Return the first matching element, or None if no element was found.
  224. """
  225. return ElementPath.find(self, path, namespaces)
  226. def findtext(self, path, default=None, namespaces=None):
  227. """Find text for first matching element by tag name or path.
  228. *path* is a string having either an element tag or an XPath,
  229. *default* is the value to return if the element was not found,
  230. *namespaces* is an optional mapping from namespace prefix to full name.
  231. Return text content of first matching element, or default value if
  232. none was found. Note that if an element is found having no text
  233. content, the empty string is returned.
  234. """
  235. return ElementPath.findtext(self, path, default, namespaces)
  236. def findall(self, path, namespaces=None):
  237. """Find all matching subelements by tag name or path.
  238. *path* is a string having either an element tag or an XPath,
  239. *namespaces* is an optional mapping from namespace prefix to full name.
  240. Returns list containing all matching elements in document order.
  241. """
  242. return ElementPath.findall(self, path, namespaces)
  243. def iterfind(self, path, namespaces=None):
  244. """Find all matching subelements by tag name or path.
  245. *path* is a string having either an element tag or an XPath,
  246. *namespaces* is an optional mapping from namespace prefix to full name.
  247. Return an iterable yielding all matching elements in document order.
  248. """
  249. return ElementPath.iterfind(self, path, namespaces)
  250. def clear(self):
  251. """Reset element.
  252. This function removes all subelements, clears all attributes, and sets
  253. the text and tail attributes to None.
  254. """
  255. self.attrib.clear()
  256. self._children = []
  257. self.text = self.tail = None
  258. def get(self, key, default=None):
  259. """Get element attribute.
  260. Equivalent to attrib.get, but some implementations may handle this a
  261. bit more efficiently. *key* is what attribute to look for, and
  262. *default* is what to return if the attribute was not found.
  263. Returns a string containing the attribute value, or the default if
  264. attribute was not found.
  265. """
  266. return self.attrib.get(key, default)
  267. def set(self, key, value):
  268. """Set element attribute.
  269. Equivalent to attrib[key] = value, but some implementations may handle
  270. this a bit more efficiently. *key* is what attribute to set, and
  271. *value* is the attribute value to set it to.
  272. """
  273. self.attrib[key] = value
  274. def keys(self):
  275. """Get list of attribute names.
  276. Names are returned in an arbitrary order, just like an ordinary
  277. Python dict. Equivalent to attrib.keys()
  278. """
  279. return self.attrib.keys()
  280. def items(self):
  281. """Get element attributes as a sequence.
  282. The attributes are returned in arbitrary order. Equivalent to
  283. attrib.items().
  284. Return a list of (name, value) tuples.
  285. """
  286. return self.attrib.items()
  287. def iter(self, tag=None):
  288. """Create tree iterator.
  289. The iterator loops over the element and all subelements in document
  290. order, returning all elements with a matching tag.
  291. If the tree structure is modified during iteration, new or removed
  292. elements may or may not be included. To get a stable set, use the
  293. list() function on the iterator, and loop over the resulting list.
  294. *tag* is what tags to look for (default is to return all elements)
  295. Return an iterator containing all the matching elements.
  296. """
  297. if tag == "*":
  298. tag = None
  299. if tag is None or self.tag == tag:
  300. yield self
  301. for e in self._children:
  302. yield from e.iter(tag)
  303. # compatibility
  304. def getiterator(self, tag=None):
  305. # Change for a DeprecationWarning in 1.4
  306. warnings.warn(
  307. "This method will be removed in future versions. "
  308. "Use 'elem.iter()' or 'list(elem.iter())' instead.",
  309. PendingDeprecationWarning, stacklevel=2
  310. )
  311. return list(self.iter(tag))
  312. def itertext(self):
  313. """Create text iterator.
  314. The iterator loops over the element and all subelements in document
  315. order, returning all inner text.
  316. """
  317. tag = self.tag
  318. if not isinstance(tag, str) and tag is not None:
  319. return
  320. t = self.text
  321. if t:
  322. yield t
  323. for e in self:
  324. yield from e.itertext()
  325. t = e.tail
  326. if t:
  327. yield t
  328. def SubElement(parent, tag, attrib={}, **extra):
  329. """Subelement factory which creates an element instance, and appends it
  330. to an existing parent.
  331. The element tag, attribute names, and attribute values can be either
  332. bytes or Unicode strings.
  333. *parent* is the parent element, *tag* is the subelements name, *attrib* is
  334. an optional directory containing element attributes, *extra* are
  335. additional attributes given as keyword arguments.
  336. """
  337. attrib = attrib.copy()
  338. attrib.update(extra)
  339. element = parent.makeelement(tag, attrib)
  340. parent.append(element)
  341. return element
  342. def Comment(text=None):
  343. """Comment element factory.
  344. This function creates a special element which the standard serializer
  345. serializes as an XML comment.
  346. *text* is a string containing the comment string.
  347. """
  348. element = Element(Comment)
  349. element.text = text
  350. return element
  351. def ProcessingInstruction(target, text=None):
  352. """Processing Instruction element factory.
  353. This function creates a special element which the standard serializer
  354. serializes as an XML comment.
  355. *target* is a string containing the processing instruction, *text* is a
  356. string containing the processing instruction contents, if any.
  357. """
  358. element = Element(ProcessingInstruction)
  359. element.text = target
  360. if text:
  361. element.text = element.text + " " + text
  362. return element
  363. PI = ProcessingInstruction
  364. class QName:
  365. """Qualified name wrapper.
  366. This class can be used to wrap a QName attribute value in order to get
  367. proper namespace handing on output.
  368. *text_or_uri* is a string containing the QName value either in the form
  369. {uri}local, or if the tag argument is given, the URI part of a QName.
  370. *tag* is an optional argument which if given, will make the first
  371. argument (text_or_uri) be interpreted as a URI, and this argument (tag)
  372. be interpreted as a local name.
  373. """
  374. def __init__(self, text_or_uri, tag=None):
  375. if tag:
  376. text_or_uri = "{%s}%s" % (text_or_uri, tag)
  377. self.text = text_or_uri
  378. def __str__(self):
  379. return self.text
  380. def __repr__(self):
  381. return '<%s %r>' % (self.__class__.__name__, self.text)
  382. def __hash__(self):
  383. return hash(self.text)
  384. def __le__(self, other):
  385. if isinstance(other, QName):
  386. return self.text <= other.text
  387. return self.text <= other
  388. def __lt__(self, other):
  389. if isinstance(other, QName):
  390. return self.text < other.text
  391. return self.text < other
  392. def __ge__(self, other):
  393. if isinstance(other, QName):
  394. return self.text >= other.text
  395. return self.text >= other
  396. def __gt__(self, other):
  397. if isinstance(other, QName):
  398. return self.text > other.text
  399. return self.text > other
  400. def __eq__(self, other):
  401. if isinstance(other, QName):
  402. return self.text == other.text
  403. return self.text == other
  404. # --------------------------------------------------------------------
  405. class ElementTree:
  406. """An XML element hierarchy.
  407. This class also provides support for serialization to and from
  408. standard XML.
  409. *element* is an optional root element node,
  410. *file* is an optional file handle or file name of an XML file whose
  411. contents will be used to initialize the tree with.
  412. """
  413. def __init__(self, element=None, file=None):
  414. # assert element is None or iselement(element)
  415. self._root = element # first node
  416. if file:
  417. self.parse(file)
  418. def getroot(self):
  419. """Return root element of this tree."""
  420. return self._root
  421. def _setroot(self, element):
  422. """Replace root element of this tree.
  423. This will discard the current contents of the tree and replace it
  424. with the given element. Use with care!
  425. """
  426. # assert iselement(element)
  427. self._root = element
  428. def parse(self, source, parser=None):
  429. """Load external XML document into element tree.
  430. *source* is a file name or file object, *parser* is an optional parser
  431. instance that defaults to XMLParser.
  432. ParseError is raised if the parser fails to parse the document.
  433. Returns the root element of the given source document.
  434. """
  435. close_source = False
  436. if not hasattr(source, "read"):
  437. source = open(source, "rb")
  438. close_source = True
  439. try:
  440. if parser is None:
  441. # If no parser was specified, create a default XMLParser
  442. parser = XMLParser()
  443. if hasattr(parser, '_parse_whole'):
  444. # The default XMLParser, when it comes from an accelerator,
  445. # can define an internal _parse_whole API for efficiency.
  446. # It can be used to parse the whole source without feeding
  447. # it with chunks.
  448. self._root = parser._parse_whole(source)
  449. return self._root
  450. while True:
  451. data = source.read(65536)
  452. if not data:
  453. break
  454. parser.feed(data)
  455. self._root = parser.close()
  456. return self._root
  457. finally:
  458. if close_source:
  459. source.close()
  460. def iter(self, tag=None):
  461. """Create and return tree iterator for the root element.
  462. The iterator loops over all elements in this tree, in document order.
  463. *tag* is a string with the tag name to iterate over
  464. (default is to return all elements).
  465. """
  466. # assert self._root is not None
  467. return self._root.iter(tag)
  468. # compatibility
  469. def getiterator(self, tag=None):
  470. # Change for a DeprecationWarning in 1.4
  471. warnings.warn(
  472. "This method will be removed in future versions. "
  473. "Use 'tree.iter()' or 'list(tree.iter())' instead.",
  474. PendingDeprecationWarning, stacklevel=2
  475. )
  476. return list(self.iter(tag))
  477. def find(self, path, namespaces=None):
  478. """Find first matching element by tag name or path.
  479. Same as getroot().find(path), which is Element.find()
  480. *path* is a string having either an element tag or an XPath,
  481. *namespaces* is an optional mapping from namespace prefix to full name.
  482. Return the first matching element, or None if no element was found.
  483. """
  484. # assert self._root is not None
  485. if path[:1] == "/":
  486. path = "." + path
  487. warnings.warn(
  488. "This search is broken in 1.3 and earlier, and will be "
  489. "fixed in a future version. If you rely on the current "
  490. "behaviour, change it to %r" % path,
  491. FutureWarning, stacklevel=2
  492. )
  493. return self._root.find(path, namespaces)
  494. def findtext(self, path, default=None, namespaces=None):
  495. """Find first matching element by tag name or path.
  496. Same as getroot().findtext(path), which is Element.findtext()
  497. *path* is a string having either an element tag or an XPath,
  498. *namespaces* is an optional mapping from namespace prefix to full name.
  499. Return the first matching element, or None if no element was found.
  500. """
  501. # assert self._root is not None
  502. if path[:1] == "/":
  503. path = "." + path
  504. warnings.warn(
  505. "This search is broken in 1.3 and earlier, and will be "
  506. "fixed in a future version. If you rely on the current "
  507. "behaviour, change it to %r" % path,
  508. FutureWarning, stacklevel=2
  509. )
  510. return self._root.findtext(path, default, namespaces)
  511. def findall(self, path, namespaces=None):
  512. """Find all matching subelements by tag name or path.
  513. Same as getroot().findall(path), which is Element.findall().
  514. *path* is a string having either an element tag or an XPath,
  515. *namespaces* is an optional mapping from namespace prefix to full name.
  516. Return list containing all matching elements in document order.
  517. """
  518. # assert self._root is not None
  519. if path[:1] == "/":
  520. path = "." + path
  521. warnings.warn(
  522. "This search is broken in 1.3 and earlier, and will be "
  523. "fixed in a future version. If you rely on the current "
  524. "behaviour, change it to %r" % path,
  525. FutureWarning, stacklevel=2
  526. )
  527. return self._root.findall(path, namespaces)
  528. def iterfind(self, path, namespaces=None):
  529. """Find all matching subelements by tag name or path.
  530. Same as getroot().iterfind(path), which is element.iterfind()
  531. *path* is a string having either an element tag or an XPath,
  532. *namespaces* is an optional mapping from namespace prefix to full name.
  533. Return an iterable yielding all matching elements in document order.
  534. """
  535. # assert self._root is not None
  536. if path[:1] == "/":
  537. path = "." + path
  538. warnings.warn(
  539. "This search is broken in 1.3 and earlier, and will be "
  540. "fixed in a future version. If you rely on the current "
  541. "behaviour, change it to %r" % path,
  542. FutureWarning, stacklevel=2
  543. )
  544. return self._root.iterfind(path, namespaces)
  545. def write(self, file_or_filename,
  546. encoding=None,
  547. xml_declaration=None,
  548. default_namespace=None,
  549. method=None, *,
  550. short_empty_elements=True):
  551. """Write element tree to a file as XML.
  552. Arguments:
  553. *file_or_filename* -- file name or a file object opened for writing
  554. *encoding* -- the output encoding (default: US-ASCII)
  555. *xml_declaration* -- bool indicating if an XML declaration should be
  556. added to the output. If None, an XML declaration
  557. is added if encoding IS NOT either of:
  558. US-ASCII, UTF-8, or Unicode
  559. *default_namespace* -- sets the default XML namespace (for "xmlns")
  560. *method* -- either "xml" (default), "html, "text", or "c14n"
  561. *short_empty_elements* -- controls the formatting of elements
  562. that contain no content. If True (default)
  563. they are emitted as a single self-closed
  564. tag, otherwise they are emitted as a pair
  565. of start/end tags
  566. """
  567. if not method:
  568. method = "xml"
  569. elif method not in _serialize:
  570. raise ValueError("unknown method %r" % method)
  571. if not encoding:
  572. if method == "c14n":
  573. encoding = "utf-8"
  574. else:
  575. encoding = "us-ascii"
  576. enc_lower = encoding.lower()
  577. with _get_writer(file_or_filename, enc_lower) as write:
  578. if method == "xml" and (xml_declaration or
  579. (xml_declaration is None and
  580. enc_lower not in ("utf-8", "us-ascii", "unicode"))):
  581. declared_encoding = encoding
  582. if enc_lower == "unicode":
  583. # Retrieve the default encoding for the xml declaration
  584. import locale
  585. declared_encoding = locale.getpreferredencoding()
  586. write("<?xml version='1.0' encoding='%s'?>\n" % (
  587. declared_encoding,))
  588. if method == "text":
  589. _serialize_text(write, self._root)
  590. else:
  591. qnames, namespaces = _namespaces(self._root, default_namespace)
  592. serialize = _serialize[method]
  593. serialize(write, self._root, qnames, namespaces,
  594. short_empty_elements=short_empty_elements)
  595. def write_c14n(self, file):
  596. # lxml.etree compatibility. use output method instead
  597. return self.write(file, method="c14n")
  598. # --------------------------------------------------------------------
  599. # serialization support
  600. @contextlib.contextmanager
  601. def _get_writer(file_or_filename, encoding):
  602. # returns text write method and release all resources after using
  603. try:
  604. write = file_or_filename.write
  605. except AttributeError:
  606. # file_or_filename is a file name
  607. if encoding == "unicode":
  608. file = open(file_or_filename, "w")
  609. else:
  610. file = open(file_or_filename, "w", encoding=encoding,
  611. errors="xmlcharrefreplace")
  612. with file:
  613. yield file.write
  614. else:
  615. # file_or_filename is a file-like object
  616. # encoding determines if it is a text or binary writer
  617. if encoding == "unicode":
  618. # use a text writer as is
  619. yield write
  620. else:
  621. # wrap a binary writer with TextIOWrapper
  622. with contextlib.ExitStack() as stack:
  623. if isinstance(file_or_filename, io.BufferedIOBase):
  624. file = file_or_filename
  625. elif isinstance(file_or_filename, io.RawIOBase):
  626. file = io.BufferedWriter(file_or_filename)
  627. # Keep the original file open when the BufferedWriter is
  628. # destroyed
  629. stack.callback(file.detach)
  630. else:
  631. # This is to handle passed objects that aren't in the
  632. # IOBase hierarchy, but just have a write method
  633. file = io.BufferedIOBase()
  634. file.writable = lambda: True
  635. file.write = write
  636. try:
  637. # TextIOWrapper uses this methods to determine
  638. # if BOM (for UTF-16, etc) should be added
  639. file.seekable = file_or_filename.seekable
  640. file.tell = file_or_filename.tell
  641. except AttributeError:
  642. pass
  643. file = io.TextIOWrapper(file,
  644. encoding=encoding,
  645. errors="xmlcharrefreplace",
  646. newline="\n")
  647. # Keep the original file open when the TextIOWrapper is
  648. # destroyed
  649. stack.callback(file.detach)
  650. yield file.write
  651. def _namespaces(elem, default_namespace=None):
  652. # identify namespaces used in this tree
  653. # maps qnames to *encoded* prefix:local names
  654. qnames = {None: None}
  655. # maps uri:s to prefixes
  656. namespaces = {}
  657. if default_namespace:
  658. namespaces[default_namespace] = ""
  659. def add_qname(qname):
  660. # calculate serialized qname representation
  661. try:
  662. if qname[:1] == "{":
  663. uri, tag = qname[1:].rsplit("}", 1)
  664. prefix = namespaces.get(uri)
  665. if prefix is None:
  666. prefix = _namespace_map.get(uri)
  667. if prefix is None:
  668. prefix = "ns%d" % len(namespaces)
  669. if prefix != "xml":
  670. namespaces[uri] = prefix
  671. if prefix:
  672. qnames[qname] = "%s:%s" % (prefix, tag)
  673. else:
  674. qnames[qname] = tag # default element
  675. else:
  676. if default_namespace:
  677. # FIXME: can this be handled in XML 1.0?
  678. raise ValueError(
  679. "cannot use non-qualified names with "
  680. "default_namespace option"
  681. )
  682. qnames[qname] = qname
  683. except TypeError:
  684. _raise_serialization_error(qname)
  685. # populate qname and namespaces table
  686. for elem in elem.iter():
  687. tag = elem.tag
  688. if isinstance(tag, QName):
  689. if tag.text not in qnames:
  690. add_qname(tag.text)
  691. elif isinstance(tag, str):
  692. if tag not in qnames:
  693. add_qname(tag)
  694. elif tag is not None and tag is not Comment and tag is not PI:
  695. _raise_serialization_error(tag)
  696. for key, value in elem.items():
  697. if isinstance(key, QName):
  698. key = key.text
  699. if key not in qnames:
  700. add_qname(key)
  701. if isinstance(value, QName) and value.text not in qnames:
  702. add_qname(value.text)
  703. text = elem.text
  704. if isinstance(text, QName) and text.text not in qnames:
  705. add_qname(text.text)
  706. return qnames, namespaces
  707. def _serialize_xml(write, elem, qnames, namespaces,
  708. short_empty_elements, **kwargs):
  709. tag = elem.tag
  710. text = elem.text
  711. if tag is Comment:
  712. write("<!--%s-->" % text)
  713. elif tag is ProcessingInstruction:
  714. write("<?%s?>" % text)
  715. else:
  716. tag = qnames[tag]
  717. if tag is None:
  718. if text:
  719. write(_escape_cdata(text))
  720. for e in elem:
  721. _serialize_xml(write, e, qnames, None,
  722. short_empty_elements=short_empty_elements)
  723. else:
  724. write("<" + tag)
  725. items = list(elem.items())
  726. if items or namespaces:
  727. if namespaces:
  728. for v, k in sorted(namespaces.items(),
  729. key=lambda x: x[1]): # sort on prefix
  730. if k:
  731. k = ":" + k
  732. write(" xmlns%s=\"%s\"" % (
  733. k,
  734. _escape_attrib(v)
  735. ))
  736. for k, v in sorted(items): # lexical order
  737. if isinstance(k, QName):
  738. k = k.text
  739. if isinstance(v, QName):
  740. v = qnames[v.text]
  741. else:
  742. v = _escape_attrib(v)
  743. write(" %s=\"%s\"" % (qnames[k], v))
  744. if text or len(elem) or not short_empty_elements:
  745. write(">")
  746. if text:
  747. write(_escape_cdata(text))
  748. for e in elem:
  749. _serialize_xml(write, e, qnames, None,
  750. short_empty_elements=short_empty_elements)
  751. write("</" + tag + ">")
  752. else:
  753. write(" />")
  754. if elem.tail:
  755. write(_escape_cdata(elem.tail))
  756. HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
  757. "img", "input", "isindex", "link", "meta", "param")
  758. try:
  759. HTML_EMPTY = set(HTML_EMPTY)
  760. except NameError:
  761. pass
  762. def _serialize_html(write, elem, qnames, namespaces, **kwargs):
  763. tag = elem.tag
  764. text = elem.text
  765. if tag is Comment:
  766. write("<!--%s-->" % _escape_cdata(text))
  767. elif tag is ProcessingInstruction:
  768. write("<?%s?>" % _escape_cdata(text))
  769. else:
  770. tag = qnames[tag]
  771. if tag is None:
  772. if text:
  773. write(_escape_cdata(text))
  774. for e in elem:
  775. _serialize_html(write, e, qnames, None)
  776. else:
  777. write("<" + tag)
  778. items = list(elem.items())
  779. if items or namespaces:
  780. if namespaces:
  781. for v, k in sorted(namespaces.items(),
  782. key=lambda x: x[1]): # sort on prefix
  783. if k:
  784. k = ":" + k
  785. write(" xmlns%s=\"%s\"" % (
  786. k,
  787. _escape_attrib(v)
  788. ))
  789. for k, v in sorted(items): # lexical order
  790. if isinstance(k, QName):
  791. k = k.text
  792. if isinstance(v, QName):
  793. v = qnames[v.text]
  794. else:
  795. v = _escape_attrib_html(v)
  796. # FIXME: handle boolean attributes
  797. write(" %s=\"%s\"" % (qnames[k], v))
  798. write(">")
  799. ltag = tag.lower()
  800. if text:
  801. if ltag == "script" or ltag == "style":
  802. write(text)
  803. else:
  804. write(_escape_cdata(text))
  805. for e in elem:
  806. _serialize_html(write, e, qnames, None)
  807. if ltag not in HTML_EMPTY:
  808. write("</" + tag + ">")
  809. if elem.tail:
  810. write(_escape_cdata(elem.tail))
  811. def _serialize_text(write, elem):
  812. for part in elem.itertext():
  813. write(part)
  814. if elem.tail:
  815. write(elem.tail)
  816. _serialize = {
  817. "xml": _serialize_xml,
  818. "html": _serialize_html,
  819. "text": _serialize_text,
  820. # this optional method is imported at the end of the module
  821. # "c14n": _serialize_c14n,
  822. }
  823. def register_namespace(prefix, uri):
  824. """Register a namespace prefix.
  825. The registry is global, and any existing mapping for either the
  826. given prefix or the namespace URI will be removed.
  827. *prefix* is the namespace prefix, *uri* is a namespace uri. Tags and
  828. attributes in this namespace will be serialized with prefix if possible.
  829. ValueError is raised if prefix is reserved or is invalid.
  830. """
  831. if re.match("ns\d+$", prefix):
  832. raise ValueError("Prefix format reserved for internal use")
  833. for k, v in list(_namespace_map.items()):
  834. if k == uri or v == prefix:
  835. del _namespace_map[k]
  836. _namespace_map[uri] = prefix
  837. _namespace_map = {
  838. # "well-known" namespace prefixes
  839. "http://www.w3.org/XML/1998/namespace": "xml",
  840. "http://www.w3.org/1999/xhtml": "html",
  841. "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
  842. "http://schemas.xmlsoap.org/wsdl/": "wsdl",
  843. # xml schema
  844. "http://www.w3.org/2001/XMLSchema": "xs",
  845. "http://www.w3.org/2001/XMLSchema-instance": "xsi",
  846. # dublin core
  847. "http://purl.org/dc/elements/1.1/": "dc",
  848. }
  849. # For tests and troubleshooting
  850. register_namespace._namespace_map = _namespace_map
  851. def _raise_serialization_error(text):
  852. raise TypeError(
  853. "cannot serialize %r (type %s)" % (text, type(text).__name__)
  854. )
  855. def _escape_cdata(text):
  856. # escape character data
  857. try:
  858. # it's worth avoiding do-nothing calls for strings that are
  859. # shorter than 500 character, or so. assume that's, by far,
  860. # the most common case in most applications.
  861. if "&" in text:
  862. text = text.replace("&", "&amp;")
  863. if "<" in text:
  864. text = text.replace("<", "&lt;")
  865. if ">" in text:
  866. text = text.replace(">", "&gt;")
  867. return text
  868. except (TypeError, AttributeError):
  869. _raise_serialization_error(text)
  870. def _escape_attrib(text):
  871. # escape attribute value
  872. try:
  873. if "&" in text:
  874. text = text.replace("&", "&amp;")
  875. if "<" in text:
  876. text = text.replace("<", "&lt;")
  877. if ">" in text:
  878. text = text.replace(">", "&gt;")
  879. if "\"" in text:
  880. text = text.replace("\"", "&quot;")
  881. if "\n" in text:
  882. text = text.replace("\n", "&#10;")
  883. return text
  884. except (TypeError, AttributeError):
  885. _raise_serialization_error(text)
  886. def _escape_attrib_html(text):
  887. # escape attribute value
  888. try:
  889. if "&" in text:
  890. text = text.replace("&", "&amp;")
  891. if ">" in text:
  892. text = text.replace(">", "&gt;")
  893. if "\"" in text:
  894. text = text.replace("\"", "&quot;")
  895. return text
  896. except (TypeError, AttributeError):
  897. _raise_serialization_error(text)
  898. # --------------------------------------------------------------------
  899. def tostring(element, encoding=None, method=None, *,
  900. short_empty_elements=True):
  901. """Generate string representation of XML element.
  902. All subelements are included. If encoding is "unicode", a string
  903. is returned. Otherwise a bytestring is returned.
  904. *element* is an Element instance, *encoding* is an optional output
  905. encoding defaulting to US-ASCII, *method* is an optional output which can
  906. be one of "xml" (default), "html", "text" or "c14n".
  907. Returns an (optionally) encoded string containing the XML data.
  908. """
  909. stream = io.StringIO() if encoding == 'unicode' else io.BytesIO()
  910. ElementTree(element).write(stream, encoding, method=method,
  911. short_empty_elements=short_empty_elements)
  912. return stream.getvalue()
  913. class _ListDataStream(io.BufferedIOBase):
  914. """An auxiliary stream accumulating into a list reference."""
  915. def __init__(self, lst):
  916. self.lst = lst
  917. def writable(self):
  918. return True
  919. def seekable(self):
  920. return True
  921. def write(self, b):
  922. self.lst.append(b)
  923. def tell(self):
  924. return len(self.lst)
  925. def tostringlist(element, encoding=None, method=None, *,
  926. short_empty_elements=True):
  927. lst = []
  928. stream = _ListDataStream(lst)
  929. ElementTree(element).write(stream, encoding, method=method,
  930. short_empty_elements=short_empty_elements)
  931. return lst
  932. def dump(elem):
  933. """Write element tree or element structure to sys.stdout.
  934. This function should be used for debugging only.
  935. *elem* is either an ElementTree, or a single Element. The exact output
  936. format is implementation dependent. In this version, it's written as an
  937. ordinary XML file.
  938. """
  939. # debugging
  940. if not isinstance(elem, ElementTree):
  941. elem = ElementTree(elem)
  942. elem.write(sys.stdout, encoding="unicode")
  943. tail = elem.getroot().tail
  944. if not tail or tail[-1] != "\n":
  945. sys.stdout.write("\n")
  946. # --------------------------------------------------------------------
  947. # parsing
  948. def parse(source, parser=None):
  949. """Parse XML document into element tree.
  950. *source* is a filename or file object containing XML data,
  951. *parser* is an optional parser instance defaulting to XMLParser.
  952. Return an ElementTree instance.
  953. """
  954. tree = ElementTree()
  955. tree.parse(source, parser)
  956. return tree
  957. def iterparse(source, events=None, parser=None):
  958. """Incrementally parse XML document into ElementTree.
  959. This class also reports what's going on to the user based on the
  960. *events* it is initialized with. The supported events are the strings
  961. "start", "end", "start-ns" and "end-ns" (the "ns" events are used to get
  962. detailed namespace information). If *events* is omitted, only
  963. "end" events are reported.
  964. *source* is a filename or file object containing XML data, *events* is
  965. a list of events to report back, *parser* is an optional parser instance.
  966. Returns an iterator providing (event, elem) pairs.
  967. """
  968. close_source = False
  969. if not hasattr(source, "read"):
  970. source = open(source, "rb")
  971. close_source = True
  972. try:
  973. return _IterParseIterator(source, events, parser, close_source)
  974. except:
  975. if close_source:
  976. source.close()
  977. raise
  978. class XMLPullParser:
  979. def __init__(self, events=None, *, _parser=None):
  980. # The _parser argument is for internal use only and must not be relied
  981. # upon in user code. It will be removed in a future release.
  982. # See http://bugs.python.org/issue17741 for more details.
  983. # _elementtree.c expects a list, not a deque
  984. self._events_queue = []
  985. self._index = 0
  986. self._parser = _parser or XMLParser(target=TreeBuilder())
  987. # wire up the parser for event reporting
  988. if events is None:
  989. events = ("end",)
  990. self._parser._setevents(self._events_queue, events)
  991. def feed(self, data):
  992. """Feed encoded data to parser."""
  993. if self._parser is None:
  994. raise ValueError("feed() called after end of stream")
  995. if data:
  996. try:
  997. self._parser.feed(data)
  998. except SyntaxError as exc:
  999. self._events_queue.append(exc)
  1000. def _close_and_return_root(self):
  1001. # iterparse needs this to set its root attribute properly :(
  1002. root = self._parser.close()
  1003. self._parser = None
  1004. return root
  1005. def close(self):
  1006. """Finish feeding data to parser.
  1007. Unlike XMLParser, does not return the root element. Use
  1008. read_events() to consume elements from XMLPullParser.
  1009. """
  1010. self._close_and_return_root()
  1011. def read_events(self):
  1012. """Return an iterator over currently available (event, elem) pairs.
  1013. Events are consumed from the internal event queue as they are
  1014. retrieved from the iterator.
  1015. """
  1016. events = self._events_queue
  1017. while True:
  1018. index = self._index
  1019. try:
  1020. event = events[self._index]
  1021. # Avoid retaining references to past events
  1022. events[self._index] = None
  1023. except IndexError:
  1024. break
  1025. index += 1
  1026. # Compact the list in a O(1) amortized fashion
  1027. # As noted above, _elementree.c needs a list, not a deque
  1028. if index * 2 >= len(events):
  1029. events[:index] = []
  1030. self._index = 0
  1031. else:
  1032. self._index = index
  1033. if isinstance(event, Exception):
  1034. raise event
  1035. else:
  1036. yield event
  1037. class _IterParseIterator:
  1038. def __init__(self, source, events, parser, close_source=False):
  1039. # Use the internal, undocumented _parser argument for now; When the
  1040. # parser argument of iterparse is removed, this can be killed.
  1041. self._parser = XMLPullParser(events=events, _parser=parser)
  1042. self._file = source
  1043. self._close_file = close_source
  1044. self.root = self._root = None
  1045. def __next__(self):
  1046. try:
  1047. while 1:
  1048. for event in self._parser.read_events():
  1049. return event
  1050. if self._parser._parser is None:
  1051. break
  1052. # load event buffer
  1053. data = self._file.read(16 * 1024)
  1054. if data:
  1055. self._parser.feed(data)
  1056. else:
  1057. self._root = self._parser._close_and_return_root()
  1058. self.root = self._root
  1059. except:
  1060. if self._close_file:
  1061. self._file.close()
  1062. raise
  1063. if self._close_file:
  1064. self._file.close()
  1065. raise StopIteration
  1066. def __iter__(self):
  1067. return self
  1068. def XML(text, parser=None):
  1069. """Parse XML document from string constant.
  1070. This function can be used to embed "XML Literals" in Python code.
  1071. *text* is a string containing XML data, *parser* is an
  1072. optional parser instance, defaulting to the standard XMLParser.
  1073. Returns an Element instance.
  1074. """
  1075. if not parser:
  1076. parser = XMLParser(target=TreeBuilder())
  1077. parser.feed(text)
  1078. return parser.close()
  1079. def XMLID(text, parser=None):
  1080. """Parse XML document from string constant for its IDs.
  1081. *text* is a string containing XML data, *parser* is an
  1082. optional parser instance, defaulting to the standard XMLParser.
  1083. Returns an (Element, dict) tuple, in which the
  1084. dict maps element id:s to elements.
  1085. """
  1086. if not parser:
  1087. parser = XMLParser(target=TreeBuilder())
  1088. parser.feed(text)
  1089. tree = parser.close()
  1090. ids = {}
  1091. for elem in tree.iter():
  1092. id = elem.get("id")
  1093. if id:
  1094. ids[id] = elem
  1095. return tree, ids
  1096. # Parse XML document from string constant. Alias for XML().
  1097. fromstring = XML
  1098. def fromstringlist(sequence, parser=None):
  1099. """Parse XML document from sequence of string fragments.
  1100. *sequence* is a list of other sequence, *parser* is an optional parser
  1101. instance, defaulting to the standard XMLParser.
  1102. Returns an Element instance.
  1103. """
  1104. if not parser:
  1105. parser = XMLParser(target=TreeBuilder())
  1106. for text in sequence:
  1107. parser.feed(text)
  1108. return parser.close()
  1109. # --------------------------------------------------------------------
  1110. class TreeBuilder:
  1111. """Generic element structure builder.
  1112. This builder converts a sequence of start, data, and end method
  1113. calls to a well-formed element structure.
  1114. You can use this class to build an element structure using a custom XML
  1115. parser, or a parser for some other XML-like format.
  1116. *element_factory* is an optional element factory which is called
  1117. to create new Element instances, as necessary.
  1118. """
  1119. def __init__(self, element_factory=None):
  1120. self._data = [] # data collector
  1121. self._elem = [] # element stack
  1122. self._last = None # last element
  1123. self._tail = None # true if we're after an end tag
  1124. if element_factory is None:
  1125. element_factory = Element
  1126. self._factory = element_factory
  1127. def close(self):
  1128. """Flush builder buffers and return toplevel document Element."""
  1129. assert len(self._elem) == 0, "missing end tags"
  1130. assert self._last is not None, "missing toplevel element"
  1131. return self._last
  1132. def _flush(self):
  1133. if self._data:
  1134. if self._last is not None:
  1135. text = "".join(self._data)
  1136. if self._tail:
  1137. assert self._last.tail is None, "internal error (tail)"
  1138. self._last.tail = text
  1139. else:
  1140. assert self._last.text is None, "internal error (text)"
  1141. self._last.text = text
  1142. self._data = []
  1143. def data(self, data):
  1144. """Add text to current element."""
  1145. self._data.append(data)
  1146. def start(self, tag, attrs):
  1147. """Open new element and return it.
  1148. *tag* is the element name, *attrs* is a dict containing element
  1149. attributes.
  1150. """
  1151. self._flush()
  1152. self._last = elem = self._factory(tag, attrs)
  1153. if self._elem:
  1154. self._elem[-1].append(elem)
  1155. self._elem.append(elem)
  1156. self._tail = 0
  1157. return elem
  1158. def end(self, tag):
  1159. """Close and return current Element.
  1160. *tag* is the element name.
  1161. """
  1162. self._flush()
  1163. self._last = self._elem.pop()
  1164. assert self._last.tag == tag,\
  1165. "end tag mismatch (expected %s, got %s)" % (
  1166. self._last.tag, tag)
  1167. self._tail = 1
  1168. return self._last
  1169. # also see ElementTree and TreeBuilder
  1170. class XMLParser:
  1171. """Element structure builder for XML source data based on the expat parser.
  1172. *html* are predefined HTML entities (deprecated and not supported),
  1173. *target* is an optional target object which defaults to an instance of the
  1174. standard TreeBuilder class, *encoding* is an optional encoding string
  1175. which if given, overrides the encoding specified in the XML file:
  1176. http://www.iana.org/assignments/character-sets
  1177. """
  1178. def __init__(self, html=0, target=None, encoding=None):
  1179. try:
  1180. from xml.parsers import expat
  1181. except ImportError:
  1182. try:
  1183. import pyexpat as expat
  1184. except ImportError:
  1185. raise ImportError(
  1186. "No module named expat; use SimpleXMLTreeBuilder instead"
  1187. )
  1188. parser = expat.ParserCreate(encoding, "}")
  1189. if target is None:
  1190. target = TreeBuilder()
  1191. # underscored names are provided for compatibility only
  1192. self.parser = self._parser = parser
  1193. self.target = self._target = target
  1194. self._error = expat.error
  1195. self._names = {} # name memo cache
  1196. # main callbacks
  1197. parser.DefaultHandlerExpand = self._default
  1198. if hasattr(target, 'start'):
  1199. parser.StartElementHandler = self._start
  1200. if hasattr(target, 'end'):
  1201. parser.EndElementHandler = self._end
  1202. if hasattr(target, 'data'):
  1203. parser.CharacterDataHandler = target.data
  1204. # miscellaneous callbacks
  1205. if hasattr(target, 'comment'):
  1206. parser.CommentHandler = target.comment
  1207. if hasattr(target, 'pi'):
  1208. parser.ProcessingInstructionHandler = target.pi
  1209. # Configure pyexpat: buffering, new-style attribute handling.
  1210. parser.buffer_text = 1
  1211. parser.ordered_attributes = 1
  1212. parser.specified_attributes = 1
  1213. self._doctype = None
  1214. self.entity = {}
  1215. try:
  1216. self.version = "Expat %d.%d.%d" % expat.version_info
  1217. except AttributeError:
  1218. pass # unknown
  1219. def _setevents(self, events_queue, events_to_report):
  1220. # Internal API for XMLPullParser
  1221. # events_to_report: a list of events to report during parsing (same as
  1222. # the *events* of XMLPullParser's constructor.
  1223. # events_queue: a list of actual parsing events that will be populated
  1224. # by the underlying parser.
  1225. #
  1226. parser = self._parser
  1227. append = events_queue.append
  1228. for event_name in events_to_report:
  1229. if event_name == "start":
  1230. parser.ordered_attributes = 1
  1231. parser.specified_attributes = 1
  1232. def handler(tag, attrib_in, event=event_name, append=append,
  1233. start=self._start):
  1234. append((event, start(tag, attrib_in)))
  1235. parser.StartElementHandler = handler
  1236. elif event_name == "end":
  1237. def handler(tag, event=event_name, append=append,
  1238. end=self._end):
  1239. append((event, end(tag)))
  1240. parser.EndElementHandler = handler
  1241. elif event_name == "start-ns":
  1242. def handler(prefix, uri, event=event_name, append=append):
  1243. append((event, (prefix or "", uri or "")))
  1244. parser.StartNamespaceDeclHandler = handler
  1245. elif event_name == "end-ns":
  1246. def handler(prefix, event=event_name, append=append):
  1247. append((event, None))
  1248. parser.EndNamespaceDeclHandler = handler
  1249. else:
  1250. raise ValueError("unknown event %r" % event_name)
  1251. def _raiseerror(self, value):
  1252. err = ParseError(value)
  1253. err.code = value.code
  1254. err.position = value.lineno, value.offset
  1255. raise err
  1256. def _fixname(self, key):
  1257. # expand qname, and convert name string to ascii, if possible
  1258. try:
  1259. name = self._names[key]
  1260. except KeyError:
  1261. name = key
  1262. if "}" in name:
  1263. name = "{" + name
  1264. self._names[key] = name
  1265. return name
  1266. def _start(self, tag, attr_list):
  1267. # Handler for expat's StartElementHandler. Since ordered_attributes
  1268. # is set, the attributes are reported as a list of alternating
  1269. # attribute name,value.
  1270. fixname = self._fixname
  1271. tag = fixname(tag)
  1272. attrib = {}
  1273. if attr_list:
  1274. for i in range(0, len(attr_list), 2):
  1275. attrib[fixname(attr_list[i])] = attr_list[i+1]
  1276. return self.target.start(tag, attrib)
  1277. def _end(self, tag):
  1278. return self.target.end(self._fixname(tag))
  1279. def _default(self, text):
  1280. prefix = text[:1]
  1281. if prefix == "&":
  1282. # deal with undefined entities
  1283. try:
  1284. data_handler = self.target.data
  1285. except AttributeError:
  1286. return
  1287. try:
  1288. data_handler(self.entity[text[1:-1]])
  1289. except KeyError:
  1290. from xml.parsers import expat
  1291. err = expat.error(
  1292. "undefined entity %s: line %d, column %d" %
  1293. (text, self.parser.ErrorLineNumber,
  1294. self.parser.ErrorColumnNumber)
  1295. )
  1296. err.code = 11 # XML_ERROR_UNDEFINED_ENTITY
  1297. err.lineno = self.parser.ErrorLineNumber
  1298. err.offset = self.parser.ErrorColumnNumber
  1299. raise err
  1300. elif prefix == "<" and text[:9] == "<!DOCTYPE":
  1301. self._doctype = [] # inside a doctype declaration
  1302. elif self._doctype is not None:
  1303. # parse doctype contents
  1304. if prefix == ">":
  1305. self._doctype = None
  1306. return
  1307. text = text.strip()
  1308. if not text:
  1309. return
  1310. self._doctype.append(text)
  1311. n = len(self._doctype)
  1312. if n > 2:
  1313. type = self._doctype[1]
  1314. if type == "PUBLIC" and n == 4:
  1315. name, type, pubid, system = self._doctype
  1316. if pubid:
  1317. pubid = pubid[1:-1]
  1318. elif type == "SYSTEM" and n == 3:
  1319. name, type, system = self._doctype
  1320. pubid = None
  1321. else:
  1322. return
  1323. if hasattr(self.target, "doctype"):
  1324. self.target.doctype(name, pubid, system[1:-1])
  1325. elif self.doctype != self._XMLParser__doctype:
  1326. # warn about deprecated call
  1327. self._XMLParser__doctype(name, pubid, system[1:-1])
  1328. self.doctype(name, pubid, system[1:-1])
  1329. self._doctype = None
  1330. def doctype(self, name, pubid, system):
  1331. """(Deprecated) Handle doctype declaration
  1332. *name* is the Doctype name, *pubid* is the public identifier,
  1333. and *system* is the system identifier.
  1334. """
  1335. warnings.warn(
  1336. "This method of XMLParser is deprecated. Define doctype() "
  1337. "method on the TreeBuilder target.",
  1338. DeprecationWarning,
  1339. )
  1340. # sentinel, if doctype is redefined in a subclass
  1341. __doctype = doctype
  1342. def feed(self, data):
  1343. """Feed encoded data to parser."""
  1344. try:
  1345. self.parser.Parse(data, 0)
  1346. except self._error as v:
  1347. self._raiseerror(v)
  1348. def close(self):
  1349. """Finish feeding data to parser and return element structure."""
  1350. try:
  1351. self.parser.Parse("", 1) # end of data
  1352. except self._error as v:
  1353. self._raiseerror(v)
  1354. try:
  1355. close_handler = self.target.close
  1356. except AttributeError:
  1357. pass
  1358. else:
  1359. return close_handler()
  1360. finally:
  1361. # get rid of circular references
  1362. del self.parser, self._parser
  1363. del self.target, self._target
  1364. # Import the C accelerators
  1365. try:
  1366. # Element is going to be shadowed by the C implementation. We need to keep
  1367. # the Python version of it accessible for some "creative" by external code
  1368. # (see tests)
  1369. _Element_Py = Element
  1370. # Element, SubElement, ParseError, TreeBuilder, XMLParser
  1371. from _elementtree import *
  1372. except ImportError:
  1373. pass