minidom.py 65 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981
  1. """Simple implementation of the Level 1 DOM.
  2. Namespaces and other minor Level 2 features are also supported.
  3. parse("foo.xml")
  4. parseString("<foo><bar/></foo>")
  5. Todo:
  6. =====
  7. * convenience methods for getting elements and text.
  8. * more testing
  9. * bring some of the writer and linearizer code into conformance with this
  10. interface
  11. * SAX 2 namespaces
  12. """
  13. import io
  14. import xml.dom
  15. from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg
  16. from xml.dom.minicompat import *
  17. from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS
  18. # This is used by the ID-cache invalidation checks; the list isn't
  19. # actually complete, since the nodes being checked will never be the
  20. # DOCUMENT_NODE or DOCUMENT_FRAGMENT_NODE. (The node being checked is
  21. # the node being added or removed, not the node being modified.)
  22. #
  23. _nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
  24. xml.dom.Node.ENTITY_REFERENCE_NODE)
  25. class Node(xml.dom.Node):
  26. namespaceURI = None # this is non-null only for elements and attributes
  27. parentNode = None
  28. ownerDocument = None
  29. nextSibling = None
  30. previousSibling = None
  31. prefix = EMPTY_PREFIX # non-null only for NS elements and attributes
  32. def __bool__(self):
  33. return True
  34. def toxml(self, encoding=None):
  35. return self.toprettyxml("", "", encoding)
  36. def toprettyxml(self, indent="\t", newl="\n", encoding=None):
  37. if encoding is None:
  38. writer = io.StringIO()
  39. else:
  40. writer = io.TextIOWrapper(io.BytesIO(),
  41. encoding=encoding,
  42. errors="xmlcharrefreplace",
  43. newline='\n')
  44. if self.nodeType == Node.DOCUMENT_NODE:
  45. # Can pass encoding only to document, to put it into XML header
  46. self.writexml(writer, "", indent, newl, encoding)
  47. else:
  48. self.writexml(writer, "", indent, newl)
  49. if encoding is None:
  50. return writer.getvalue()
  51. else:
  52. return writer.detach().getvalue()
  53. def hasChildNodes(self):
  54. return bool(self.childNodes)
  55. def _get_childNodes(self):
  56. return self.childNodes
  57. def _get_firstChild(self):
  58. if self.childNodes:
  59. return self.childNodes[0]
  60. def _get_lastChild(self):
  61. if self.childNodes:
  62. return self.childNodes[-1]
  63. def insertBefore(self, newChild, refChild):
  64. if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
  65. for c in tuple(newChild.childNodes):
  66. self.insertBefore(c, refChild)
  67. ### The DOM does not clearly specify what to return in this case
  68. return newChild
  69. if newChild.nodeType not in self._child_node_types:
  70. raise xml.dom.HierarchyRequestErr(
  71. "%s cannot be child of %s" % (repr(newChild), repr(self)))
  72. if newChild.parentNode is not None:
  73. newChild.parentNode.removeChild(newChild)
  74. if refChild is None:
  75. self.appendChild(newChild)
  76. else:
  77. try:
  78. index = self.childNodes.index(refChild)
  79. except ValueError:
  80. raise xml.dom.NotFoundErr()
  81. if newChild.nodeType in _nodeTypes_with_children:
  82. _clear_id_cache(self)
  83. self.childNodes.insert(index, newChild)
  84. newChild.nextSibling = refChild
  85. refChild.previousSibling = newChild
  86. if index:
  87. node = self.childNodes[index-1]
  88. node.nextSibling = newChild
  89. newChild.previousSibling = node
  90. else:
  91. newChild.previousSibling = None
  92. newChild.parentNode = self
  93. return newChild
  94. def appendChild(self, node):
  95. if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
  96. for c in tuple(node.childNodes):
  97. self.appendChild(c)
  98. ### The DOM does not clearly specify what to return in this case
  99. return node
  100. if node.nodeType not in self._child_node_types:
  101. raise xml.dom.HierarchyRequestErr(
  102. "%s cannot be child of %s" % (repr(node), repr(self)))
  103. elif node.nodeType in _nodeTypes_with_children:
  104. _clear_id_cache(self)
  105. if node.parentNode is not None:
  106. node.parentNode.removeChild(node)
  107. _append_child(self, node)
  108. node.nextSibling = None
  109. return node
  110. def replaceChild(self, newChild, oldChild):
  111. if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
  112. refChild = oldChild.nextSibling
  113. self.removeChild(oldChild)
  114. return self.insertBefore(newChild, refChild)
  115. if newChild.nodeType not in self._child_node_types:
  116. raise xml.dom.HierarchyRequestErr(
  117. "%s cannot be child of %s" % (repr(newChild), repr(self)))
  118. if newChild is oldChild:
  119. return
  120. if newChild.parentNode is not None:
  121. newChild.parentNode.removeChild(newChild)
  122. try:
  123. index = self.childNodes.index(oldChild)
  124. except ValueError:
  125. raise xml.dom.NotFoundErr()
  126. self.childNodes[index] = newChild
  127. newChild.parentNode = self
  128. oldChild.parentNode = None
  129. if (newChild.nodeType in _nodeTypes_with_children
  130. or oldChild.nodeType in _nodeTypes_with_children):
  131. _clear_id_cache(self)
  132. newChild.nextSibling = oldChild.nextSibling
  133. newChild.previousSibling = oldChild.previousSibling
  134. oldChild.nextSibling = None
  135. oldChild.previousSibling = None
  136. if newChild.previousSibling:
  137. newChild.previousSibling.nextSibling = newChild
  138. if newChild.nextSibling:
  139. newChild.nextSibling.previousSibling = newChild
  140. return oldChild
  141. def removeChild(self, oldChild):
  142. try:
  143. self.childNodes.remove(oldChild)
  144. except ValueError:
  145. raise xml.dom.NotFoundErr()
  146. if oldChild.nextSibling is not None:
  147. oldChild.nextSibling.previousSibling = oldChild.previousSibling
  148. if oldChild.previousSibling is not None:
  149. oldChild.previousSibling.nextSibling = oldChild.nextSibling
  150. oldChild.nextSibling = oldChild.previousSibling = None
  151. if oldChild.nodeType in _nodeTypes_with_children:
  152. _clear_id_cache(self)
  153. oldChild.parentNode = None
  154. return oldChild
  155. def normalize(self):
  156. L = []
  157. for child in self.childNodes:
  158. if child.nodeType == Node.TEXT_NODE:
  159. if not child.data:
  160. # empty text node; discard
  161. if L:
  162. L[-1].nextSibling = child.nextSibling
  163. if child.nextSibling:
  164. child.nextSibling.previousSibling = child.previousSibling
  165. child.unlink()
  166. elif L and L[-1].nodeType == child.nodeType:
  167. # collapse text node
  168. node = L[-1]
  169. node.data = node.data + child.data
  170. node.nextSibling = child.nextSibling
  171. if child.nextSibling:
  172. child.nextSibling.previousSibling = node
  173. child.unlink()
  174. else:
  175. L.append(child)
  176. else:
  177. L.append(child)
  178. if child.nodeType == Node.ELEMENT_NODE:
  179. child.normalize()
  180. self.childNodes[:] = L
  181. def cloneNode(self, deep):
  182. return _clone_node(self, deep, self.ownerDocument or self)
  183. def isSupported(self, feature, version):
  184. return self.ownerDocument.implementation.hasFeature(feature, version)
  185. def _get_localName(self):
  186. # Overridden in Element and Attr where localName can be Non-Null
  187. return None
  188. # Node interfaces from Level 3 (WD 9 April 2002)
  189. def isSameNode(self, other):
  190. return self is other
  191. def getInterface(self, feature):
  192. if self.isSupported(feature, None):
  193. return self
  194. else:
  195. return None
  196. # The "user data" functions use a dictionary that is only present
  197. # if some user data has been set, so be careful not to assume it
  198. # exists.
  199. def getUserData(self, key):
  200. try:
  201. return self._user_data[key][0]
  202. except (AttributeError, KeyError):
  203. return None
  204. def setUserData(self, key, data, handler):
  205. old = None
  206. try:
  207. d = self._user_data
  208. except AttributeError:
  209. d = {}
  210. self._user_data = d
  211. if key in d:
  212. old = d[key][0]
  213. if data is None:
  214. # ignore handlers passed for None
  215. handler = None
  216. if old is not None:
  217. del d[key]
  218. else:
  219. d[key] = (data, handler)
  220. return old
  221. def _call_user_data_handler(self, operation, src, dst):
  222. if hasattr(self, "_user_data"):
  223. for key, (data, handler) in list(self._user_data.items()):
  224. if handler is not None:
  225. handler.handle(operation, key, data, src, dst)
  226. # minidom-specific API:
  227. def unlink(self):
  228. self.parentNode = self.ownerDocument = None
  229. if self.childNodes:
  230. for child in self.childNodes:
  231. child.unlink()
  232. self.childNodes = NodeList()
  233. self.previousSibling = None
  234. self.nextSibling = None
  235. # A Node is its own context manager, to ensure that an unlink() call occurs.
  236. # This is similar to how a file object works.
  237. def __enter__(self):
  238. return self
  239. def __exit__(self, et, ev, tb):
  240. self.unlink()
  241. defproperty(Node, "firstChild", doc="First child node, or None.")
  242. defproperty(Node, "lastChild", doc="Last child node, or None.")
  243. defproperty(Node, "localName", doc="Namespace-local name of this node.")
  244. def _append_child(self, node):
  245. # fast path with less checks; usable by DOM builders if careful
  246. childNodes = self.childNodes
  247. if childNodes:
  248. last = childNodes[-1]
  249. node.previousSibling = last
  250. last.nextSibling = node
  251. childNodes.append(node)
  252. node.parentNode = self
  253. def _in_document(node):
  254. # return True iff node is part of a document tree
  255. while node is not None:
  256. if node.nodeType == Node.DOCUMENT_NODE:
  257. return True
  258. node = node.parentNode
  259. return False
  260. def _write_data(writer, data):
  261. "Writes datachars to writer."
  262. if data:
  263. data = data.replace("&", "&amp;").replace("<", "&lt;"). \
  264. replace("\"", "&quot;").replace(">", "&gt;")
  265. writer.write(data)
  266. def _get_elements_by_tagName_helper(parent, name, rc):
  267. for node in parent.childNodes:
  268. if node.nodeType == Node.ELEMENT_NODE and \
  269. (name == "*" or node.tagName == name):
  270. rc.append(node)
  271. _get_elements_by_tagName_helper(node, name, rc)
  272. return rc
  273. def _get_elements_by_tagName_ns_helper(parent, nsURI, localName, rc):
  274. for node in parent.childNodes:
  275. if node.nodeType == Node.ELEMENT_NODE:
  276. if ((localName == "*" or node.localName == localName) and
  277. (nsURI == "*" or node.namespaceURI == nsURI)):
  278. rc.append(node)
  279. _get_elements_by_tagName_ns_helper(node, nsURI, localName, rc)
  280. return rc
  281. class DocumentFragment(Node):
  282. nodeType = Node.DOCUMENT_FRAGMENT_NODE
  283. nodeName = "#document-fragment"
  284. nodeValue = None
  285. attributes = None
  286. parentNode = None
  287. _child_node_types = (Node.ELEMENT_NODE,
  288. Node.TEXT_NODE,
  289. Node.CDATA_SECTION_NODE,
  290. Node.ENTITY_REFERENCE_NODE,
  291. Node.PROCESSING_INSTRUCTION_NODE,
  292. Node.COMMENT_NODE,
  293. Node.NOTATION_NODE)
  294. def __init__(self):
  295. self.childNodes = NodeList()
  296. class Attr(Node):
  297. __slots__=('_name', '_value', 'namespaceURI',
  298. '_prefix', 'childNodes', '_localName', 'ownerDocument', 'ownerElement')
  299. nodeType = Node.ATTRIBUTE_NODE
  300. attributes = None
  301. specified = False
  302. _is_id = False
  303. _child_node_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE)
  304. def __init__(self, qName, namespaceURI=EMPTY_NAMESPACE, localName=None,
  305. prefix=None):
  306. self.ownerElement = None
  307. self._name = qName
  308. self.namespaceURI = namespaceURI
  309. self._prefix = prefix
  310. self.childNodes = NodeList()
  311. # Add the single child node that represents the value of the attr
  312. self.childNodes.append(Text())
  313. # nodeValue and value are set elsewhere
  314. def _get_localName(self):
  315. try:
  316. return self._localName
  317. except AttributeError:
  318. return self.nodeName.split(":", 1)[-1]
  319. def _get_specified(self):
  320. return self.specified
  321. def _get_name(self):
  322. return self._name
  323. def _set_name(self, value):
  324. self._name = value
  325. if self.ownerElement is not None:
  326. _clear_id_cache(self.ownerElement)
  327. nodeName = name = property(_get_name, _set_name)
  328. def _get_value(self):
  329. return self._value
  330. def _set_value(self, value):
  331. self._value = value
  332. self.childNodes[0].data = value
  333. if self.ownerElement is not None:
  334. _clear_id_cache(self.ownerElement)
  335. self.childNodes[0].data = value
  336. nodeValue = value = property(_get_value, _set_value)
  337. def _get_prefix(self):
  338. return self._prefix
  339. def _set_prefix(self, prefix):
  340. nsuri = self.namespaceURI
  341. if prefix == "xmlns":
  342. if nsuri and nsuri != XMLNS_NAMESPACE:
  343. raise xml.dom.NamespaceErr(
  344. "illegal use of 'xmlns' prefix for the wrong namespace")
  345. self._prefix = prefix
  346. if prefix is None:
  347. newName = self.localName
  348. else:
  349. newName = "%s:%s" % (prefix, self.localName)
  350. if self.ownerElement:
  351. _clear_id_cache(self.ownerElement)
  352. self.name = newName
  353. prefix = property(_get_prefix, _set_prefix)
  354. def unlink(self):
  355. # This implementation does not call the base implementation
  356. # since most of that is not needed, and the expense of the
  357. # method call is not warranted. We duplicate the removal of
  358. # children, but that's all we needed from the base class.
  359. elem = self.ownerElement
  360. if elem is not None:
  361. del elem._attrs[self.nodeName]
  362. del elem._attrsNS[(self.namespaceURI, self.localName)]
  363. if self._is_id:
  364. self._is_id = False
  365. elem._magic_id_nodes -= 1
  366. self.ownerDocument._magic_id_count -= 1
  367. for child in self.childNodes:
  368. child.unlink()
  369. del self.childNodes[:]
  370. def _get_isId(self):
  371. if self._is_id:
  372. return True
  373. doc = self.ownerDocument
  374. elem = self.ownerElement
  375. if doc is None or elem is None:
  376. return False
  377. info = doc._get_elem_info(elem)
  378. if info is None:
  379. return False
  380. if self.namespaceURI:
  381. return info.isIdNS(self.namespaceURI, self.localName)
  382. else:
  383. return info.isId(self.nodeName)
  384. def _get_schemaType(self):
  385. doc = self.ownerDocument
  386. elem = self.ownerElement
  387. if doc is None or elem is None:
  388. return _no_type
  389. info = doc._get_elem_info(elem)
  390. if info is None:
  391. return _no_type
  392. if self.namespaceURI:
  393. return info.getAttributeTypeNS(self.namespaceURI, self.localName)
  394. else:
  395. return info.getAttributeType(self.nodeName)
  396. defproperty(Attr, "isId", doc="True if this attribute is an ID.")
  397. defproperty(Attr, "localName", doc="Namespace-local name of this attribute.")
  398. defproperty(Attr, "schemaType", doc="Schema type for this attribute.")
  399. class NamedNodeMap(object):
  400. """The attribute list is a transient interface to the underlying
  401. dictionaries. Mutations here will change the underlying element's
  402. dictionary.
  403. Ordering is imposed artificially and does not reflect the order of
  404. attributes as found in an input document.
  405. """
  406. __slots__ = ('_attrs', '_attrsNS', '_ownerElement')
  407. def __init__(self, attrs, attrsNS, ownerElement):
  408. self._attrs = attrs
  409. self._attrsNS = attrsNS
  410. self._ownerElement = ownerElement
  411. def _get_length(self):
  412. return len(self._attrs)
  413. def item(self, index):
  414. try:
  415. return self[list(self._attrs.keys())[index]]
  416. except IndexError:
  417. return None
  418. def items(self):
  419. L = []
  420. for node in self._attrs.values():
  421. L.append((node.nodeName, node.value))
  422. return L
  423. def itemsNS(self):
  424. L = []
  425. for node in self._attrs.values():
  426. L.append(((node.namespaceURI, node.localName), node.value))
  427. return L
  428. def __contains__(self, key):
  429. if isinstance(key, str):
  430. return key in self._attrs
  431. else:
  432. return key in self._attrsNS
  433. def keys(self):
  434. return self._attrs.keys()
  435. def keysNS(self):
  436. return self._attrsNS.keys()
  437. def values(self):
  438. return self._attrs.values()
  439. def get(self, name, value=None):
  440. return self._attrs.get(name, value)
  441. __len__ = _get_length
  442. def _cmp(self, other):
  443. if self._attrs is getattr(other, "_attrs", None):
  444. return 0
  445. else:
  446. return (id(self) > id(other)) - (id(self) < id(other))
  447. def __eq__(self, other):
  448. return self._cmp(other) == 0
  449. def __ge__(self, other):
  450. return self._cmp(other) >= 0
  451. def __gt__(self, other):
  452. return self._cmp(other) > 0
  453. def __le__(self, other):
  454. return self._cmp(other) <= 0
  455. def __lt__(self, other):
  456. return self._cmp(other) < 0
  457. def __getitem__(self, attname_or_tuple):
  458. if isinstance(attname_or_tuple, tuple):
  459. return self._attrsNS[attname_or_tuple]
  460. else:
  461. return self._attrs[attname_or_tuple]
  462. # same as set
  463. def __setitem__(self, attname, value):
  464. if isinstance(value, str):
  465. try:
  466. node = self._attrs[attname]
  467. except KeyError:
  468. node = Attr(attname)
  469. node.ownerDocument = self._ownerElement.ownerDocument
  470. self.setNamedItem(node)
  471. node.value = value
  472. else:
  473. if not isinstance(value, Attr):
  474. raise TypeError("value must be a string or Attr object")
  475. node = value
  476. self.setNamedItem(node)
  477. def getNamedItem(self, name):
  478. try:
  479. return self._attrs[name]
  480. except KeyError:
  481. return None
  482. def getNamedItemNS(self, namespaceURI, localName):
  483. try:
  484. return self._attrsNS[(namespaceURI, localName)]
  485. except KeyError:
  486. return None
  487. def removeNamedItem(self, name):
  488. n = self.getNamedItem(name)
  489. if n is not None:
  490. _clear_id_cache(self._ownerElement)
  491. del self._attrs[n.nodeName]
  492. del self._attrsNS[(n.namespaceURI, n.localName)]
  493. if hasattr(n, 'ownerElement'):
  494. n.ownerElement = None
  495. return n
  496. else:
  497. raise xml.dom.NotFoundErr()
  498. def removeNamedItemNS(self, namespaceURI, localName):
  499. n = self.getNamedItemNS(namespaceURI, localName)
  500. if n is not None:
  501. _clear_id_cache(self._ownerElement)
  502. del self._attrsNS[(n.namespaceURI, n.localName)]
  503. del self._attrs[n.nodeName]
  504. if hasattr(n, 'ownerElement'):
  505. n.ownerElement = None
  506. return n
  507. else:
  508. raise xml.dom.NotFoundErr()
  509. def setNamedItem(self, node):
  510. if not isinstance(node, Attr):
  511. raise xml.dom.HierarchyRequestErr(
  512. "%s cannot be child of %s" % (repr(node), repr(self)))
  513. old = self._attrs.get(node.name)
  514. if old:
  515. old.unlink()
  516. self._attrs[node.name] = node
  517. self._attrsNS[(node.namespaceURI, node.localName)] = node
  518. node.ownerElement = self._ownerElement
  519. _clear_id_cache(node.ownerElement)
  520. return old
  521. def setNamedItemNS(self, node):
  522. return self.setNamedItem(node)
  523. def __delitem__(self, attname_or_tuple):
  524. node = self[attname_or_tuple]
  525. _clear_id_cache(node.ownerElement)
  526. node.unlink()
  527. def __getstate__(self):
  528. return self._attrs, self._attrsNS, self._ownerElement
  529. def __setstate__(self, state):
  530. self._attrs, self._attrsNS, self._ownerElement = state
  531. defproperty(NamedNodeMap, "length",
  532. doc="Number of nodes in the NamedNodeMap.")
  533. AttributeList = NamedNodeMap
  534. class TypeInfo(object):
  535. __slots__ = 'namespace', 'name'
  536. def __init__(self, namespace, name):
  537. self.namespace = namespace
  538. self.name = name
  539. def __repr__(self):
  540. if self.namespace:
  541. return "<%s %r (from %r)>" % (self.__class__.__name__, self.name,
  542. self.namespace)
  543. else:
  544. return "<%s %r>" % (self.__class__.__name__, self.name)
  545. def _get_name(self):
  546. return self.name
  547. def _get_namespace(self):
  548. return self.namespace
  549. _no_type = TypeInfo(None, None)
  550. class Element(Node):
  551. __slots__=('ownerDocument', 'parentNode', 'tagName', 'nodeName', 'prefix',
  552. 'namespaceURI', '_localName', 'childNodes', '_attrs', '_attrsNS',
  553. 'nextSibling', 'previousSibling')
  554. nodeType = Node.ELEMENT_NODE
  555. nodeValue = None
  556. schemaType = _no_type
  557. _magic_id_nodes = 0
  558. _child_node_types = (Node.ELEMENT_NODE,
  559. Node.PROCESSING_INSTRUCTION_NODE,
  560. Node.COMMENT_NODE,
  561. Node.TEXT_NODE,
  562. Node.CDATA_SECTION_NODE,
  563. Node.ENTITY_REFERENCE_NODE)
  564. def __init__(self, tagName, namespaceURI=EMPTY_NAMESPACE, prefix=None,
  565. localName=None):
  566. self.parentNode = None
  567. self.tagName = self.nodeName = tagName
  568. self.prefix = prefix
  569. self.namespaceURI = namespaceURI
  570. self.childNodes = NodeList()
  571. self.nextSibling = self.previousSibling = None
  572. # Attribute dictionaries are lazily created
  573. # attributes are double-indexed:
  574. # tagName -> Attribute
  575. # URI,localName -> Attribute
  576. # in the future: consider lazy generation
  577. # of attribute objects this is too tricky
  578. # for now because of headaches with
  579. # namespaces.
  580. self._attrs = None
  581. self._attrsNS = None
  582. def _ensure_attributes(self):
  583. if self._attrs is None:
  584. self._attrs = {}
  585. self._attrsNS = {}
  586. def _get_localName(self):
  587. try:
  588. return self._localName
  589. except AttributeError:
  590. return self.tagName.split(":", 1)[-1]
  591. def _get_tagName(self):
  592. return self.tagName
  593. def unlink(self):
  594. if self._attrs is not None:
  595. for attr in list(self._attrs.values()):
  596. attr.unlink()
  597. self._attrs = None
  598. self._attrsNS = None
  599. Node.unlink(self)
  600. def getAttribute(self, attname):
  601. if self._attrs is None:
  602. return ""
  603. try:
  604. return self._attrs[attname].value
  605. except KeyError:
  606. return ""
  607. def getAttributeNS(self, namespaceURI, localName):
  608. if self._attrsNS is None:
  609. return ""
  610. try:
  611. return self._attrsNS[(namespaceURI, localName)].value
  612. except KeyError:
  613. return ""
  614. def setAttribute(self, attname, value):
  615. attr = self.getAttributeNode(attname)
  616. if attr is None:
  617. attr = Attr(attname)
  618. attr.value = value # also sets nodeValue
  619. attr.ownerDocument = self.ownerDocument
  620. self.setAttributeNode(attr)
  621. elif value != attr.value:
  622. attr.value = value
  623. if attr.isId:
  624. _clear_id_cache(self)
  625. def setAttributeNS(self, namespaceURI, qualifiedName, value):
  626. prefix, localname = _nssplit(qualifiedName)
  627. attr = self.getAttributeNodeNS(namespaceURI, localname)
  628. if attr is None:
  629. attr = Attr(qualifiedName, namespaceURI, localname, prefix)
  630. attr.value = value
  631. attr.ownerDocument = self.ownerDocument
  632. self.setAttributeNode(attr)
  633. else:
  634. if value != attr.value:
  635. attr.value = value
  636. if attr.isId:
  637. _clear_id_cache(self)
  638. if attr.prefix != prefix:
  639. attr.prefix = prefix
  640. attr.nodeName = qualifiedName
  641. def getAttributeNode(self, attrname):
  642. if self._attrs is None:
  643. return None
  644. return self._attrs.get(attrname)
  645. def getAttributeNodeNS(self, namespaceURI, localName):
  646. if self._attrsNS is None:
  647. return None
  648. return self._attrsNS.get((namespaceURI, localName))
  649. def setAttributeNode(self, attr):
  650. if attr.ownerElement not in (None, self):
  651. raise xml.dom.InuseAttributeErr("attribute node already owned")
  652. self._ensure_attributes()
  653. old1 = self._attrs.get(attr.name, None)
  654. if old1 is not None:
  655. self.removeAttributeNode(old1)
  656. old2 = self._attrsNS.get((attr.namespaceURI, attr.localName), None)
  657. if old2 is not None and old2 is not old1:
  658. self.removeAttributeNode(old2)
  659. _set_attribute_node(self, attr)
  660. if old1 is not attr:
  661. # It might have already been part of this node, in which case
  662. # it doesn't represent a change, and should not be returned.
  663. return old1
  664. if old2 is not attr:
  665. return old2
  666. setAttributeNodeNS = setAttributeNode
  667. def removeAttribute(self, name):
  668. if self._attrsNS is None:
  669. raise xml.dom.NotFoundErr()
  670. try:
  671. attr = self._attrs[name]
  672. except KeyError:
  673. raise xml.dom.NotFoundErr()
  674. self.removeAttributeNode(attr)
  675. def removeAttributeNS(self, namespaceURI, localName):
  676. if self._attrsNS is None:
  677. raise xml.dom.NotFoundErr()
  678. try:
  679. attr = self._attrsNS[(namespaceURI, localName)]
  680. except KeyError:
  681. raise xml.dom.NotFoundErr()
  682. self.removeAttributeNode(attr)
  683. def removeAttributeNode(self, node):
  684. if node is None:
  685. raise xml.dom.NotFoundErr()
  686. try:
  687. self._attrs[node.name]
  688. except KeyError:
  689. raise xml.dom.NotFoundErr()
  690. _clear_id_cache(self)
  691. node.unlink()
  692. # Restore this since the node is still useful and otherwise
  693. # unlinked
  694. node.ownerDocument = self.ownerDocument
  695. removeAttributeNodeNS = removeAttributeNode
  696. def hasAttribute(self, name):
  697. if self._attrs is None:
  698. return False
  699. return name in self._attrs
  700. def hasAttributeNS(self, namespaceURI, localName):
  701. if self._attrsNS is None:
  702. return False
  703. return (namespaceURI, localName) in self._attrsNS
  704. def getElementsByTagName(self, name):
  705. return _get_elements_by_tagName_helper(self, name, NodeList())
  706. def getElementsByTagNameNS(self, namespaceURI, localName):
  707. return _get_elements_by_tagName_ns_helper(
  708. self, namespaceURI, localName, NodeList())
  709. def __repr__(self):
  710. return "<DOM Element: %s at %#x>" % (self.tagName, id(self))
  711. def writexml(self, writer, indent="", addindent="", newl=""):
  712. # indent = current indentation
  713. # addindent = indentation to add to higher levels
  714. # newl = newline string
  715. writer.write(indent+"<" + self.tagName)
  716. attrs = self._get_attributes()
  717. a_names = sorted(attrs.keys())
  718. for a_name in a_names:
  719. writer.write(" %s=\"" % a_name)
  720. _write_data(writer, attrs[a_name].value)
  721. writer.write("\"")
  722. if self.childNodes:
  723. writer.write(">")
  724. if (len(self.childNodes) == 1 and
  725. self.childNodes[0].nodeType == Node.TEXT_NODE):
  726. self.childNodes[0].writexml(writer, '', '', '')
  727. else:
  728. writer.write(newl)
  729. for node in self.childNodes:
  730. node.writexml(writer, indent+addindent, addindent, newl)
  731. writer.write(indent)
  732. writer.write("</%s>%s" % (self.tagName, newl))
  733. else:
  734. writer.write("/>%s"%(newl))
  735. def _get_attributes(self):
  736. self._ensure_attributes()
  737. return NamedNodeMap(self._attrs, self._attrsNS, self)
  738. def hasAttributes(self):
  739. if self._attrs:
  740. return True
  741. else:
  742. return False
  743. # DOM Level 3 attributes, based on the 22 Oct 2002 draft
  744. def setIdAttribute(self, name):
  745. idAttr = self.getAttributeNode(name)
  746. self.setIdAttributeNode(idAttr)
  747. def setIdAttributeNS(self, namespaceURI, localName):
  748. idAttr = self.getAttributeNodeNS(namespaceURI, localName)
  749. self.setIdAttributeNode(idAttr)
  750. def setIdAttributeNode(self, idAttr):
  751. if idAttr is None or not self.isSameNode(idAttr.ownerElement):
  752. raise xml.dom.NotFoundErr()
  753. if _get_containing_entref(self) is not None:
  754. raise xml.dom.NoModificationAllowedErr()
  755. if not idAttr._is_id:
  756. idAttr._is_id = True
  757. self._magic_id_nodes += 1
  758. self.ownerDocument._magic_id_count += 1
  759. _clear_id_cache(self)
  760. defproperty(Element, "attributes",
  761. doc="NamedNodeMap of attributes on the element.")
  762. defproperty(Element, "localName",
  763. doc="Namespace-local name of this element.")
  764. def _set_attribute_node(element, attr):
  765. _clear_id_cache(element)
  766. element._ensure_attributes()
  767. element._attrs[attr.name] = attr
  768. element._attrsNS[(attr.namespaceURI, attr.localName)] = attr
  769. # This creates a circular reference, but Element.unlink()
  770. # breaks the cycle since the references to the attribute
  771. # dictionaries are tossed.
  772. attr.ownerElement = element
  773. class Childless:
  774. """Mixin that makes childless-ness easy to implement and avoids
  775. the complexity of the Node methods that deal with children.
  776. """
  777. __slots__ = ()
  778. attributes = None
  779. childNodes = EmptyNodeList()
  780. firstChild = None
  781. lastChild = None
  782. def _get_firstChild(self):
  783. return None
  784. def _get_lastChild(self):
  785. return None
  786. def appendChild(self, node):
  787. raise xml.dom.HierarchyRequestErr(
  788. self.nodeName + " nodes cannot have children")
  789. def hasChildNodes(self):
  790. return False
  791. def insertBefore(self, newChild, refChild):
  792. raise xml.dom.HierarchyRequestErr(
  793. self.nodeName + " nodes do not have children")
  794. def removeChild(self, oldChild):
  795. raise xml.dom.NotFoundErr(
  796. self.nodeName + " nodes do not have children")
  797. def normalize(self):
  798. # For childless nodes, normalize() has nothing to do.
  799. pass
  800. def replaceChild(self, newChild, oldChild):
  801. raise xml.dom.HierarchyRequestErr(
  802. self.nodeName + " nodes do not have children")
  803. class ProcessingInstruction(Childless, Node):
  804. nodeType = Node.PROCESSING_INSTRUCTION_NODE
  805. __slots__ = ('target', 'data')
  806. def __init__(self, target, data):
  807. self.target = target
  808. self.data = data
  809. # nodeValue is an alias for data
  810. def _get_nodeValue(self):
  811. return self.data
  812. def _set_nodeValue(self, value):
  813. self.data = value
  814. nodeValue = property(_get_nodeValue, _set_nodeValue)
  815. # nodeName is an alias for target
  816. def _get_nodeName(self):
  817. return self.target
  818. def _set_nodeName(self, value):
  819. self.target = value
  820. nodeName = property(_get_nodeName, _set_nodeName)
  821. def writexml(self, writer, indent="", addindent="", newl=""):
  822. writer.write("%s<?%s %s?>%s" % (indent,self.target, self.data, newl))
  823. class CharacterData(Childless, Node):
  824. __slots__=('_data', 'ownerDocument','parentNode', 'previousSibling', 'nextSibling')
  825. def __init__(self):
  826. self.ownerDocument = self.parentNode = None
  827. self.previousSibling = self.nextSibling = None
  828. self._data = ''
  829. Node.__init__(self)
  830. def _get_length(self):
  831. return len(self.data)
  832. __len__ = _get_length
  833. def _get_data(self):
  834. return self._data
  835. def _set_data(self, data):
  836. self._data = data
  837. data = nodeValue = property(_get_data, _set_data)
  838. def __repr__(self):
  839. data = self.data
  840. if len(data) > 10:
  841. dotdotdot = "..."
  842. else:
  843. dotdotdot = ""
  844. return '<DOM %s node "%r%s">' % (
  845. self.__class__.__name__, data[0:10], dotdotdot)
  846. def substringData(self, offset, count):
  847. if offset < 0:
  848. raise xml.dom.IndexSizeErr("offset cannot be negative")
  849. if offset >= len(self.data):
  850. raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  851. if count < 0:
  852. raise xml.dom.IndexSizeErr("count cannot be negative")
  853. return self.data[offset:offset+count]
  854. def appendData(self, arg):
  855. self.data = self.data + arg
  856. def insertData(self, offset, arg):
  857. if offset < 0:
  858. raise xml.dom.IndexSizeErr("offset cannot be negative")
  859. if offset >= len(self.data):
  860. raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  861. if arg:
  862. self.data = "%s%s%s" % (
  863. self.data[:offset], arg, self.data[offset:])
  864. def deleteData(self, offset, count):
  865. if offset < 0:
  866. raise xml.dom.IndexSizeErr("offset cannot be negative")
  867. if offset >= len(self.data):
  868. raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  869. if count < 0:
  870. raise xml.dom.IndexSizeErr("count cannot be negative")
  871. if count:
  872. self.data = self.data[:offset] + self.data[offset+count:]
  873. def replaceData(self, offset, count, arg):
  874. if offset < 0:
  875. raise xml.dom.IndexSizeErr("offset cannot be negative")
  876. if offset >= len(self.data):
  877. raise xml.dom.IndexSizeErr("offset cannot be beyond end of data")
  878. if count < 0:
  879. raise xml.dom.IndexSizeErr("count cannot be negative")
  880. if count:
  881. self.data = "%s%s%s" % (
  882. self.data[:offset], arg, self.data[offset+count:])
  883. defproperty(CharacterData, "length", doc="Length of the string data.")
  884. class Text(CharacterData):
  885. __slots__ = ()
  886. nodeType = Node.TEXT_NODE
  887. nodeName = "#text"
  888. attributes = None
  889. def splitText(self, offset):
  890. if offset < 0 or offset > len(self.data):
  891. raise xml.dom.IndexSizeErr("illegal offset value")
  892. newText = self.__class__()
  893. newText.data = self.data[offset:]
  894. newText.ownerDocument = self.ownerDocument
  895. next = self.nextSibling
  896. if self.parentNode and self in self.parentNode.childNodes:
  897. if next is None:
  898. self.parentNode.appendChild(newText)
  899. else:
  900. self.parentNode.insertBefore(newText, next)
  901. self.data = self.data[:offset]
  902. return newText
  903. def writexml(self, writer, indent="", addindent="", newl=""):
  904. _write_data(writer, "%s%s%s" % (indent, self.data, newl))
  905. # DOM Level 3 (WD 9 April 2002)
  906. def _get_wholeText(self):
  907. L = [self.data]
  908. n = self.previousSibling
  909. while n is not None:
  910. if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
  911. L.insert(0, n.data)
  912. n = n.previousSibling
  913. else:
  914. break
  915. n = self.nextSibling
  916. while n is not None:
  917. if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
  918. L.append(n.data)
  919. n = n.nextSibling
  920. else:
  921. break
  922. return ''.join(L)
  923. def replaceWholeText(self, content):
  924. # XXX This needs to be seriously changed if minidom ever
  925. # supports EntityReference nodes.
  926. parent = self.parentNode
  927. n = self.previousSibling
  928. while n is not None:
  929. if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
  930. next = n.previousSibling
  931. parent.removeChild(n)
  932. n = next
  933. else:
  934. break
  935. n = self.nextSibling
  936. if not content:
  937. parent.removeChild(self)
  938. while n is not None:
  939. if n.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE):
  940. next = n.nextSibling
  941. parent.removeChild(n)
  942. n = next
  943. else:
  944. break
  945. if content:
  946. self.data = content
  947. return self
  948. else:
  949. return None
  950. def _get_isWhitespaceInElementContent(self):
  951. if self.data.strip():
  952. return False
  953. elem = _get_containing_element(self)
  954. if elem is None:
  955. return False
  956. info = self.ownerDocument._get_elem_info(elem)
  957. if info is None:
  958. return False
  959. else:
  960. return info.isElementContent()
  961. defproperty(Text, "isWhitespaceInElementContent",
  962. doc="True iff this text node contains only whitespace"
  963. " and is in element content.")
  964. defproperty(Text, "wholeText",
  965. doc="The text of all logically-adjacent text nodes.")
  966. def _get_containing_element(node):
  967. c = node.parentNode
  968. while c is not None:
  969. if c.nodeType == Node.ELEMENT_NODE:
  970. return c
  971. c = c.parentNode
  972. return None
  973. def _get_containing_entref(node):
  974. c = node.parentNode
  975. while c is not None:
  976. if c.nodeType == Node.ENTITY_REFERENCE_NODE:
  977. return c
  978. c = c.parentNode
  979. return None
  980. class Comment(CharacterData):
  981. nodeType = Node.COMMENT_NODE
  982. nodeName = "#comment"
  983. def __init__(self, data):
  984. CharacterData.__init__(self)
  985. self._data = data
  986. def writexml(self, writer, indent="", addindent="", newl=""):
  987. if "--" in self.data:
  988. raise ValueError("'--' is not allowed in a comment node")
  989. writer.write("%s<!--%s-->%s" % (indent, self.data, newl))
  990. class CDATASection(Text):
  991. __slots__ = ()
  992. nodeType = Node.CDATA_SECTION_NODE
  993. nodeName = "#cdata-section"
  994. def writexml(self, writer, indent="", addindent="", newl=""):
  995. if self.data.find("]]>") >= 0:
  996. raise ValueError("']]>' not allowed in a CDATA section")
  997. writer.write("<![CDATA[%s]]>" % self.data)
  998. class ReadOnlySequentialNamedNodeMap(object):
  999. __slots__ = '_seq',
  1000. def __init__(self, seq=()):
  1001. # seq should be a list or tuple
  1002. self._seq = seq
  1003. def __len__(self):
  1004. return len(self._seq)
  1005. def _get_length(self):
  1006. return len(self._seq)
  1007. def getNamedItem(self, name):
  1008. for n in self._seq:
  1009. if n.nodeName == name:
  1010. return n
  1011. def getNamedItemNS(self, namespaceURI, localName):
  1012. for n in self._seq:
  1013. if n.namespaceURI == namespaceURI and n.localName == localName:
  1014. return n
  1015. def __getitem__(self, name_or_tuple):
  1016. if isinstance(name_or_tuple, tuple):
  1017. node = self.getNamedItemNS(*name_or_tuple)
  1018. else:
  1019. node = self.getNamedItem(name_or_tuple)
  1020. if node is None:
  1021. raise KeyError(name_or_tuple)
  1022. return node
  1023. def item(self, index):
  1024. if index < 0:
  1025. return None
  1026. try:
  1027. return self._seq[index]
  1028. except IndexError:
  1029. return None
  1030. def removeNamedItem(self, name):
  1031. raise xml.dom.NoModificationAllowedErr(
  1032. "NamedNodeMap instance is read-only")
  1033. def removeNamedItemNS(self, namespaceURI, localName):
  1034. raise xml.dom.NoModificationAllowedErr(
  1035. "NamedNodeMap instance is read-only")
  1036. def setNamedItem(self, node):
  1037. raise xml.dom.NoModificationAllowedErr(
  1038. "NamedNodeMap instance is read-only")
  1039. def setNamedItemNS(self, node):
  1040. raise xml.dom.NoModificationAllowedErr(
  1041. "NamedNodeMap instance is read-only")
  1042. def __getstate__(self):
  1043. return [self._seq]
  1044. def __setstate__(self, state):
  1045. self._seq = state[0]
  1046. defproperty(ReadOnlySequentialNamedNodeMap, "length",
  1047. doc="Number of entries in the NamedNodeMap.")
  1048. class Identified:
  1049. """Mix-in class that supports the publicId and systemId attributes."""
  1050. __slots__ = 'publicId', 'systemId'
  1051. def _identified_mixin_init(self, publicId, systemId):
  1052. self.publicId = publicId
  1053. self.systemId = systemId
  1054. def _get_publicId(self):
  1055. return self.publicId
  1056. def _get_systemId(self):
  1057. return self.systemId
  1058. class DocumentType(Identified, Childless, Node):
  1059. nodeType = Node.DOCUMENT_TYPE_NODE
  1060. nodeValue = None
  1061. name = None
  1062. publicId = None
  1063. systemId = None
  1064. internalSubset = None
  1065. def __init__(self, qualifiedName):
  1066. self.entities = ReadOnlySequentialNamedNodeMap()
  1067. self.notations = ReadOnlySequentialNamedNodeMap()
  1068. if qualifiedName:
  1069. prefix, localname = _nssplit(qualifiedName)
  1070. self.name = localname
  1071. self.nodeName = self.name
  1072. def _get_internalSubset(self):
  1073. return self.internalSubset
  1074. def cloneNode(self, deep):
  1075. if self.ownerDocument is None:
  1076. # it's ok
  1077. clone = DocumentType(None)
  1078. clone.name = self.name
  1079. clone.nodeName = self.name
  1080. operation = xml.dom.UserDataHandler.NODE_CLONED
  1081. if deep:
  1082. clone.entities._seq = []
  1083. clone.notations._seq = []
  1084. for n in self.notations._seq:
  1085. notation = Notation(n.nodeName, n.publicId, n.systemId)
  1086. clone.notations._seq.append(notation)
  1087. n._call_user_data_handler(operation, n, notation)
  1088. for e in self.entities._seq:
  1089. entity = Entity(e.nodeName, e.publicId, e.systemId,
  1090. e.notationName)
  1091. entity.actualEncoding = e.actualEncoding
  1092. entity.encoding = e.encoding
  1093. entity.version = e.version
  1094. clone.entities._seq.append(entity)
  1095. e._call_user_data_handler(operation, n, entity)
  1096. self._call_user_data_handler(operation, self, clone)
  1097. return clone
  1098. else:
  1099. return None
  1100. def writexml(self, writer, indent="", addindent="", newl=""):
  1101. writer.write("<!DOCTYPE ")
  1102. writer.write(self.name)
  1103. if self.publicId:
  1104. writer.write("%s PUBLIC '%s'%s '%s'"
  1105. % (newl, self.publicId, newl, self.systemId))
  1106. elif self.systemId:
  1107. writer.write("%s SYSTEM '%s'" % (newl, self.systemId))
  1108. if self.internalSubset is not None:
  1109. writer.write(" [")
  1110. writer.write(self.internalSubset)
  1111. writer.write("]")
  1112. writer.write(">"+newl)
  1113. class Entity(Identified, Node):
  1114. attributes = None
  1115. nodeType = Node.ENTITY_NODE
  1116. nodeValue = None
  1117. actualEncoding = None
  1118. encoding = None
  1119. version = None
  1120. def __init__(self, name, publicId, systemId, notation):
  1121. self.nodeName = name
  1122. self.notationName = notation
  1123. self.childNodes = NodeList()
  1124. self._identified_mixin_init(publicId, systemId)
  1125. def _get_actualEncoding(self):
  1126. return self.actualEncoding
  1127. def _get_encoding(self):
  1128. return self.encoding
  1129. def _get_version(self):
  1130. return self.version
  1131. def appendChild(self, newChild):
  1132. raise xml.dom.HierarchyRequestErr(
  1133. "cannot append children to an entity node")
  1134. def insertBefore(self, newChild, refChild):
  1135. raise xml.dom.HierarchyRequestErr(
  1136. "cannot insert children below an entity node")
  1137. def removeChild(self, oldChild):
  1138. raise xml.dom.HierarchyRequestErr(
  1139. "cannot remove children from an entity node")
  1140. def replaceChild(self, newChild, oldChild):
  1141. raise xml.dom.HierarchyRequestErr(
  1142. "cannot replace children of an entity node")
  1143. class Notation(Identified, Childless, Node):
  1144. nodeType = Node.NOTATION_NODE
  1145. nodeValue = None
  1146. def __init__(self, name, publicId, systemId):
  1147. self.nodeName = name
  1148. self._identified_mixin_init(publicId, systemId)
  1149. class DOMImplementation(DOMImplementationLS):
  1150. _features = [("core", "1.0"),
  1151. ("core", "2.0"),
  1152. ("core", None),
  1153. ("xml", "1.0"),
  1154. ("xml", "2.0"),
  1155. ("xml", None),
  1156. ("ls-load", "3.0"),
  1157. ("ls-load", None),
  1158. ]
  1159. def hasFeature(self, feature, version):
  1160. if version == "":
  1161. version = None
  1162. return (feature.lower(), version) in self._features
  1163. def createDocument(self, namespaceURI, qualifiedName, doctype):
  1164. if doctype and doctype.parentNode is not None:
  1165. raise xml.dom.WrongDocumentErr(
  1166. "doctype object owned by another DOM tree")
  1167. doc = self._create_document()
  1168. add_root_element = not (namespaceURI is None
  1169. and qualifiedName is None
  1170. and doctype is None)
  1171. if not qualifiedName and add_root_element:
  1172. # The spec is unclear what to raise here; SyntaxErr
  1173. # would be the other obvious candidate. Since Xerces raises
  1174. # InvalidCharacterErr, and since SyntaxErr is not listed
  1175. # for createDocument, that seems to be the better choice.
  1176. # XXX: need to check for illegal characters here and in
  1177. # createElement.
  1178. # DOM Level III clears this up when talking about the return value
  1179. # of this function. If namespaceURI, qName and DocType are
  1180. # Null the document is returned without a document element
  1181. # Otherwise if doctype or namespaceURI are not None
  1182. # Then we go back to the above problem
  1183. raise xml.dom.InvalidCharacterErr("Element with no name")
  1184. if add_root_element:
  1185. prefix, localname = _nssplit(qualifiedName)
  1186. if prefix == "xml" \
  1187. and namespaceURI != "http://www.w3.org/XML/1998/namespace":
  1188. raise xml.dom.NamespaceErr("illegal use of 'xml' prefix")
  1189. if prefix and not namespaceURI:
  1190. raise xml.dom.NamespaceErr(
  1191. "illegal use of prefix without namespaces")
  1192. element = doc.createElementNS(namespaceURI, qualifiedName)
  1193. if doctype:
  1194. doc.appendChild(doctype)
  1195. doc.appendChild(element)
  1196. if doctype:
  1197. doctype.parentNode = doctype.ownerDocument = doc
  1198. doc.doctype = doctype
  1199. doc.implementation = self
  1200. return doc
  1201. def createDocumentType(self, qualifiedName, publicId, systemId):
  1202. doctype = DocumentType(qualifiedName)
  1203. doctype.publicId = publicId
  1204. doctype.systemId = systemId
  1205. return doctype
  1206. # DOM Level 3 (WD 9 April 2002)
  1207. def getInterface(self, feature):
  1208. if self.hasFeature(feature, None):
  1209. return self
  1210. else:
  1211. return None
  1212. # internal
  1213. def _create_document(self):
  1214. return Document()
  1215. class ElementInfo(object):
  1216. """Object that represents content-model information for an element.
  1217. This implementation is not expected to be used in practice; DOM
  1218. builders should provide implementations which do the right thing
  1219. using information available to it.
  1220. """
  1221. __slots__ = 'tagName',
  1222. def __init__(self, name):
  1223. self.tagName = name
  1224. def getAttributeType(self, aname):
  1225. return _no_type
  1226. def getAttributeTypeNS(self, namespaceURI, localName):
  1227. return _no_type
  1228. def isElementContent(self):
  1229. return False
  1230. def isEmpty(self):
  1231. """Returns true iff this element is declared to have an EMPTY
  1232. content model."""
  1233. return False
  1234. def isId(self, aname):
  1235. """Returns true iff the named attribute is a DTD-style ID."""
  1236. return False
  1237. def isIdNS(self, namespaceURI, localName):
  1238. """Returns true iff the identified attribute is a DTD-style ID."""
  1239. return False
  1240. def __getstate__(self):
  1241. return self.tagName
  1242. def __setstate__(self, state):
  1243. self.tagName = state
  1244. def _clear_id_cache(node):
  1245. if node.nodeType == Node.DOCUMENT_NODE:
  1246. node._id_cache.clear()
  1247. node._id_search_stack = None
  1248. elif _in_document(node):
  1249. node.ownerDocument._id_cache.clear()
  1250. node.ownerDocument._id_search_stack= None
  1251. class Document(Node, DocumentLS):
  1252. __slots__ = ('_elem_info', 'doctype',
  1253. '_id_search_stack', 'childNodes', '_id_cache')
  1254. _child_node_types = (Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE,
  1255. Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE)
  1256. implementation = DOMImplementation()
  1257. nodeType = Node.DOCUMENT_NODE
  1258. nodeName = "#document"
  1259. nodeValue = None
  1260. attributes = None
  1261. parentNode = None
  1262. previousSibling = nextSibling = None
  1263. # Document attributes from Level 3 (WD 9 April 2002)
  1264. actualEncoding = None
  1265. encoding = None
  1266. standalone = None
  1267. version = None
  1268. strictErrorChecking = False
  1269. errorHandler = None
  1270. documentURI = None
  1271. _magic_id_count = 0
  1272. def __init__(self):
  1273. self.doctype = None
  1274. self.childNodes = NodeList()
  1275. # mapping of (namespaceURI, localName) -> ElementInfo
  1276. # and tagName -> ElementInfo
  1277. self._elem_info = {}
  1278. self._id_cache = {}
  1279. self._id_search_stack = None
  1280. def _get_elem_info(self, element):
  1281. if element.namespaceURI:
  1282. key = element.namespaceURI, element.localName
  1283. else:
  1284. key = element.tagName
  1285. return self._elem_info.get(key)
  1286. def _get_actualEncoding(self):
  1287. return self.actualEncoding
  1288. def _get_doctype(self):
  1289. return self.doctype
  1290. def _get_documentURI(self):
  1291. return self.documentURI
  1292. def _get_encoding(self):
  1293. return self.encoding
  1294. def _get_errorHandler(self):
  1295. return self.errorHandler
  1296. def _get_standalone(self):
  1297. return self.standalone
  1298. def _get_strictErrorChecking(self):
  1299. return self.strictErrorChecking
  1300. def _get_version(self):
  1301. return self.version
  1302. def appendChild(self, node):
  1303. if node.nodeType not in self._child_node_types:
  1304. raise xml.dom.HierarchyRequestErr(
  1305. "%s cannot be child of %s" % (repr(node), repr(self)))
  1306. if node.parentNode is not None:
  1307. # This needs to be done before the next test since this
  1308. # may *be* the document element, in which case it should
  1309. # end up re-ordered to the end.
  1310. node.parentNode.removeChild(node)
  1311. if node.nodeType == Node.ELEMENT_NODE \
  1312. and self._get_documentElement():
  1313. raise xml.dom.HierarchyRequestErr(
  1314. "two document elements disallowed")
  1315. return Node.appendChild(self, node)
  1316. def removeChild(self, oldChild):
  1317. try:
  1318. self.childNodes.remove(oldChild)
  1319. except ValueError:
  1320. raise xml.dom.NotFoundErr()
  1321. oldChild.nextSibling = oldChild.previousSibling = None
  1322. oldChild.parentNode = None
  1323. if self.documentElement is oldChild:
  1324. self.documentElement = None
  1325. return oldChild
  1326. def _get_documentElement(self):
  1327. for node in self.childNodes:
  1328. if node.nodeType == Node.ELEMENT_NODE:
  1329. return node
  1330. def unlink(self):
  1331. if self.doctype is not None:
  1332. self.doctype.unlink()
  1333. self.doctype = None
  1334. Node.unlink(self)
  1335. def cloneNode(self, deep):
  1336. if not deep:
  1337. return None
  1338. clone = self.implementation.createDocument(None, None, None)
  1339. clone.encoding = self.encoding
  1340. clone.standalone = self.standalone
  1341. clone.version = self.version
  1342. for n in self.childNodes:
  1343. childclone = _clone_node(n, deep, clone)
  1344. assert childclone.ownerDocument.isSameNode(clone)
  1345. clone.childNodes.append(childclone)
  1346. if childclone.nodeType == Node.DOCUMENT_NODE:
  1347. assert clone.documentElement is None
  1348. elif childclone.nodeType == Node.DOCUMENT_TYPE_NODE:
  1349. assert clone.doctype is None
  1350. clone.doctype = childclone
  1351. childclone.parentNode = clone
  1352. self._call_user_data_handler(xml.dom.UserDataHandler.NODE_CLONED,
  1353. self, clone)
  1354. return clone
  1355. def createDocumentFragment(self):
  1356. d = DocumentFragment()
  1357. d.ownerDocument = self
  1358. return d
  1359. def createElement(self, tagName):
  1360. e = Element(tagName)
  1361. e.ownerDocument = self
  1362. return e
  1363. def createTextNode(self, data):
  1364. if not isinstance(data, str):
  1365. raise TypeError("node contents must be a string")
  1366. t = Text()
  1367. t.data = data
  1368. t.ownerDocument = self
  1369. return t
  1370. def createCDATASection(self, data):
  1371. if not isinstance(data, str):
  1372. raise TypeError("node contents must be a string")
  1373. c = CDATASection()
  1374. c.data = data
  1375. c.ownerDocument = self
  1376. return c
  1377. def createComment(self, data):
  1378. c = Comment(data)
  1379. c.ownerDocument = self
  1380. return c
  1381. def createProcessingInstruction(self, target, data):
  1382. p = ProcessingInstruction(target, data)
  1383. p.ownerDocument = self
  1384. return p
  1385. def createAttribute(self, qName):
  1386. a = Attr(qName)
  1387. a.ownerDocument = self
  1388. a.value = ""
  1389. return a
  1390. def createElementNS(self, namespaceURI, qualifiedName):
  1391. prefix, localName = _nssplit(qualifiedName)
  1392. e = Element(qualifiedName, namespaceURI, prefix)
  1393. e.ownerDocument = self
  1394. return e
  1395. def createAttributeNS(self, namespaceURI, qualifiedName):
  1396. prefix, localName = _nssplit(qualifiedName)
  1397. a = Attr(qualifiedName, namespaceURI, localName, prefix)
  1398. a.ownerDocument = self
  1399. a.value = ""
  1400. return a
  1401. # A couple of implementation-specific helpers to create node types
  1402. # not supported by the W3C DOM specs:
  1403. def _create_entity(self, name, publicId, systemId, notationName):
  1404. e = Entity(name, publicId, systemId, notationName)
  1405. e.ownerDocument = self
  1406. return e
  1407. def _create_notation(self, name, publicId, systemId):
  1408. n = Notation(name, publicId, systemId)
  1409. n.ownerDocument = self
  1410. return n
  1411. def getElementById(self, id):
  1412. if id in self._id_cache:
  1413. return self._id_cache[id]
  1414. if not (self._elem_info or self._magic_id_count):
  1415. return None
  1416. stack = self._id_search_stack
  1417. if stack is None:
  1418. # we never searched before, or the cache has been cleared
  1419. stack = [self.documentElement]
  1420. self._id_search_stack = stack
  1421. elif not stack:
  1422. # Previous search was completed and cache is still valid;
  1423. # no matching node.
  1424. return None
  1425. result = None
  1426. while stack:
  1427. node = stack.pop()
  1428. # add child elements to stack for continued searching
  1429. stack.extend([child for child in node.childNodes
  1430. if child.nodeType in _nodeTypes_with_children])
  1431. # check this node
  1432. info = self._get_elem_info(node)
  1433. if info:
  1434. # We have to process all ID attributes before
  1435. # returning in order to get all the attributes set to
  1436. # be IDs using Element.setIdAttribute*().
  1437. for attr in node.attributes.values():
  1438. if attr.namespaceURI:
  1439. if info.isIdNS(attr.namespaceURI, attr.localName):
  1440. self._id_cache[attr.value] = node
  1441. if attr.value == id:
  1442. result = node
  1443. elif not node._magic_id_nodes:
  1444. break
  1445. elif info.isId(attr.name):
  1446. self._id_cache[attr.value] = node
  1447. if attr.value == id:
  1448. result = node
  1449. elif not node._magic_id_nodes:
  1450. break
  1451. elif attr._is_id:
  1452. self._id_cache[attr.value] = node
  1453. if attr.value == id:
  1454. result = node
  1455. elif node._magic_id_nodes == 1:
  1456. break
  1457. elif node._magic_id_nodes:
  1458. for attr in node.attributes.values():
  1459. if attr._is_id:
  1460. self._id_cache[attr.value] = node
  1461. if attr.value == id:
  1462. result = node
  1463. if result is not None:
  1464. break
  1465. return result
  1466. def getElementsByTagName(self, name):
  1467. return _get_elements_by_tagName_helper(self, name, NodeList())
  1468. def getElementsByTagNameNS(self, namespaceURI, localName):
  1469. return _get_elements_by_tagName_ns_helper(
  1470. self, namespaceURI, localName, NodeList())
  1471. def isSupported(self, feature, version):
  1472. return self.implementation.hasFeature(feature, version)
  1473. def importNode(self, node, deep):
  1474. if node.nodeType == Node.DOCUMENT_NODE:
  1475. raise xml.dom.NotSupportedErr("cannot import document nodes")
  1476. elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
  1477. raise xml.dom.NotSupportedErr("cannot import document type nodes")
  1478. return _clone_node(node, deep, self)
  1479. def writexml(self, writer, indent="", addindent="", newl="", encoding=None):
  1480. if encoding is None:
  1481. writer.write('<?xml version="1.0" ?>'+newl)
  1482. else:
  1483. writer.write('<?xml version="1.0" encoding="%s"?>%s' % (
  1484. encoding, newl))
  1485. for node in self.childNodes:
  1486. node.writexml(writer, indent, addindent, newl)
  1487. # DOM Level 3 (WD 9 April 2002)
  1488. def renameNode(self, n, namespaceURI, name):
  1489. if n.ownerDocument is not self:
  1490. raise xml.dom.WrongDocumentErr(
  1491. "cannot rename nodes from other documents;\n"
  1492. "expected %s,\nfound %s" % (self, n.ownerDocument))
  1493. if n.nodeType not in (Node.ELEMENT_NODE, Node.ATTRIBUTE_NODE):
  1494. raise xml.dom.NotSupportedErr(
  1495. "renameNode() only applies to element and attribute nodes")
  1496. if namespaceURI != EMPTY_NAMESPACE:
  1497. if ':' in name:
  1498. prefix, localName = name.split(':', 1)
  1499. if ( prefix == "xmlns"
  1500. and namespaceURI != xml.dom.XMLNS_NAMESPACE):
  1501. raise xml.dom.NamespaceErr(
  1502. "illegal use of 'xmlns' prefix")
  1503. else:
  1504. if ( name == "xmlns"
  1505. and namespaceURI != xml.dom.XMLNS_NAMESPACE
  1506. and n.nodeType == Node.ATTRIBUTE_NODE):
  1507. raise xml.dom.NamespaceErr(
  1508. "illegal use of the 'xmlns' attribute")
  1509. prefix = None
  1510. localName = name
  1511. else:
  1512. prefix = None
  1513. localName = None
  1514. if n.nodeType == Node.ATTRIBUTE_NODE:
  1515. element = n.ownerElement
  1516. if element is not None:
  1517. is_id = n._is_id
  1518. element.removeAttributeNode(n)
  1519. else:
  1520. element = None
  1521. n.prefix = prefix
  1522. n._localName = localName
  1523. n.namespaceURI = namespaceURI
  1524. n.nodeName = name
  1525. if n.nodeType == Node.ELEMENT_NODE:
  1526. n.tagName = name
  1527. else:
  1528. # attribute node
  1529. n.name = name
  1530. if element is not None:
  1531. element.setAttributeNode(n)
  1532. if is_id:
  1533. element.setIdAttributeNode(n)
  1534. # It's not clear from a semantic perspective whether we should
  1535. # call the user data handlers for the NODE_RENAMED event since
  1536. # we're re-using the existing node. The draft spec has been
  1537. # interpreted as meaning "no, don't call the handler unless a
  1538. # new node is created."
  1539. return n
  1540. defproperty(Document, "documentElement",
  1541. doc="Top-level element of this document.")
  1542. def _clone_node(node, deep, newOwnerDocument):
  1543. """
  1544. Clone a node and give it the new owner document.
  1545. Called by Node.cloneNode and Document.importNode
  1546. """
  1547. if node.ownerDocument.isSameNode(newOwnerDocument):
  1548. operation = xml.dom.UserDataHandler.NODE_CLONED
  1549. else:
  1550. operation = xml.dom.UserDataHandler.NODE_IMPORTED
  1551. if node.nodeType == Node.ELEMENT_NODE:
  1552. clone = newOwnerDocument.createElementNS(node.namespaceURI,
  1553. node.nodeName)
  1554. for attr in node.attributes.values():
  1555. clone.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value)
  1556. a = clone.getAttributeNodeNS(attr.namespaceURI, attr.localName)
  1557. a.specified = attr.specified
  1558. if deep:
  1559. for child in node.childNodes:
  1560. c = _clone_node(child, deep, newOwnerDocument)
  1561. clone.appendChild(c)
  1562. elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
  1563. clone = newOwnerDocument.createDocumentFragment()
  1564. if deep:
  1565. for child in node.childNodes:
  1566. c = _clone_node(child, deep, newOwnerDocument)
  1567. clone.appendChild(c)
  1568. elif node.nodeType == Node.TEXT_NODE:
  1569. clone = newOwnerDocument.createTextNode(node.data)
  1570. elif node.nodeType == Node.CDATA_SECTION_NODE:
  1571. clone = newOwnerDocument.createCDATASection(node.data)
  1572. elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE:
  1573. clone = newOwnerDocument.createProcessingInstruction(node.target,
  1574. node.data)
  1575. elif node.nodeType == Node.COMMENT_NODE:
  1576. clone = newOwnerDocument.createComment(node.data)
  1577. elif node.nodeType == Node.ATTRIBUTE_NODE:
  1578. clone = newOwnerDocument.createAttributeNS(node.namespaceURI,
  1579. node.nodeName)
  1580. clone.specified = True
  1581. clone.value = node.value
  1582. elif node.nodeType == Node.DOCUMENT_TYPE_NODE:
  1583. assert node.ownerDocument is not newOwnerDocument
  1584. operation = xml.dom.UserDataHandler.NODE_IMPORTED
  1585. clone = newOwnerDocument.implementation.createDocumentType(
  1586. node.name, node.publicId, node.systemId)
  1587. clone.ownerDocument = newOwnerDocument
  1588. if deep:
  1589. clone.entities._seq = []
  1590. clone.notations._seq = []
  1591. for n in node.notations._seq:
  1592. notation = Notation(n.nodeName, n.publicId, n.systemId)
  1593. notation.ownerDocument = newOwnerDocument
  1594. clone.notations._seq.append(notation)
  1595. if hasattr(n, '_call_user_data_handler'):
  1596. n._call_user_data_handler(operation, n, notation)
  1597. for e in node.entities._seq:
  1598. entity = Entity(e.nodeName, e.publicId, e.systemId,
  1599. e.notationName)
  1600. entity.actualEncoding = e.actualEncoding
  1601. entity.encoding = e.encoding
  1602. entity.version = e.version
  1603. entity.ownerDocument = newOwnerDocument
  1604. clone.entities._seq.append(entity)
  1605. if hasattr(e, '_call_user_data_handler'):
  1606. e._call_user_data_handler(operation, n, entity)
  1607. else:
  1608. # Note the cloning of Document and DocumentType nodes is
  1609. # implementation specific. minidom handles those cases
  1610. # directly in the cloneNode() methods.
  1611. raise xml.dom.NotSupportedErr("Cannot clone node %s" % repr(node))
  1612. # Check for _call_user_data_handler() since this could conceivably
  1613. # used with other DOM implementations (one of the FourThought
  1614. # DOMs, perhaps?).
  1615. if hasattr(node, '_call_user_data_handler'):
  1616. node._call_user_data_handler(operation, node, clone)
  1617. return clone
  1618. def _nssplit(qualifiedName):
  1619. fields = qualifiedName.split(':', 1)
  1620. if len(fields) == 2:
  1621. return fields
  1622. else:
  1623. return (None, fields[0])
  1624. def _do_pulldom_parse(func, args, kwargs):
  1625. events = func(*args, **kwargs)
  1626. toktype, rootNode = events.getEvent()
  1627. events.expandNode(rootNode)
  1628. events.clear()
  1629. return rootNode
  1630. def parse(file, parser=None, bufsize=None):
  1631. """Parse a file into a DOM by filename or file object."""
  1632. if parser is None and not bufsize:
  1633. from xml.dom import expatbuilder
  1634. return expatbuilder.parse(file)
  1635. else:
  1636. from xml.dom import pulldom
  1637. return _do_pulldom_parse(pulldom.parse, (file,),
  1638. {'parser': parser, 'bufsize': bufsize})
  1639. def parseString(string, parser=None):
  1640. """Parse a file into a DOM from a string."""
  1641. if parser is None:
  1642. from xml.dom import expatbuilder
  1643. return expatbuilder.parseString(string)
  1644. else:
  1645. from xml.dom import pulldom
  1646. return _do_pulldom_parse(pulldom.parseString, (string,),
  1647. {'parser': parser})
  1648. def getDOMImplementation(features=None):
  1649. if features:
  1650. if isinstance(features, str):
  1651. features = domreg._parse_feature_string(features)
  1652. for f, v in features:
  1653. if not Document.implementation.hasFeature(f, v):
  1654. return None
  1655. return Document.implementation