minidom.py 66 KB

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