minidom.py 67 KB

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