test_minidom.py 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694
  1. # test for xml.dom.minidom
  2. import copy
  3. import pickle
  4. import io
  5. from test import support
  6. import unittest
  7. import pyexpat
  8. import xml.dom.minidom
  9. from xml.dom.minidom import parse, Attr, Node, Document, parseString
  10. from xml.dom.minidom import getDOMImplementation
  11. from xml.parsers.expat import ExpatError
  12. tstfile = support.findfile("test.xml", subdir="xmltestdata")
  13. sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
  14. "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
  15. " 'http://xml.python.org/system' [\n"
  16. " <!ELEMENT e EMPTY>\n"
  17. " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
  18. "]><doc attr='value'> text\n"
  19. "<?pi sample?> <!-- comment --> <e/> </doc>")
  20. # The tests of DocumentType importing use these helpers to construct
  21. # the documents to work with, since not all DOM builders actually
  22. # create the DocumentType nodes.
  23. def create_doc_without_doctype(doctype=None):
  24. return getDOMImplementation().createDocument(None, "doc", doctype)
  25. def create_nonempty_doctype():
  26. doctype = getDOMImplementation().createDocumentType("doc", None, None)
  27. doctype.entities._seq = []
  28. doctype.notations._seq = []
  29. notation = xml.dom.minidom.Notation("my-notation", None,
  30. "http://xml.python.org/notations/my")
  31. doctype.notations._seq.append(notation)
  32. entity = xml.dom.minidom.Entity("my-entity", None,
  33. "http://xml.python.org/entities/my",
  34. "my-notation")
  35. entity.version = "1.0"
  36. entity.encoding = "utf-8"
  37. entity.actualEncoding = "us-ascii"
  38. doctype.entities._seq.append(entity)
  39. return doctype
  40. def create_doc_with_doctype():
  41. doctype = create_nonempty_doctype()
  42. doc = create_doc_without_doctype(doctype)
  43. doctype.entities.item(0).ownerDocument = doc
  44. doctype.notations.item(0).ownerDocument = doc
  45. return doc
  46. class MinidomTest(unittest.TestCase):
  47. def confirm(self, test, testname = "Test"):
  48. self.assertTrue(test, testname)
  49. def checkWholeText(self, node, s):
  50. t = node.wholeText
  51. self.confirm(t == s, "looking for %r, found %r" % (s, t))
  52. def testDocumentAsyncAttr(self):
  53. doc = Document()
  54. self.assertFalse(doc.async_)
  55. self.assertFalse(Document.async_)
  56. def testParseFromBinaryFile(self):
  57. with open(tstfile, 'rb') as file:
  58. dom = parse(file)
  59. dom.unlink()
  60. self.confirm(isinstance(dom, Document))
  61. def testParseFromTextFile(self):
  62. with open(tstfile, 'r', encoding='iso-8859-1') as file:
  63. dom = parse(file)
  64. dom.unlink()
  65. self.confirm(isinstance(dom, Document))
  66. def testAttrModeSetsParamsAsAttrs(self):
  67. attr = Attr("qName", "namespaceURI", "localName", "prefix")
  68. self.assertEqual(attr.name, "qName")
  69. self.assertEqual(attr.namespaceURI, "namespaceURI")
  70. self.assertEqual(attr.prefix, "prefix")
  71. self.assertEqual(attr.localName, "localName")
  72. def testAttrModeSetsNonOptionalAttrs(self):
  73. attr = Attr("qName", "namespaceURI", None, "prefix")
  74. self.assertEqual(attr.name, "qName")
  75. self.assertEqual(attr.namespaceURI, "namespaceURI")
  76. self.assertEqual(attr.prefix, "prefix")
  77. self.assertEqual(attr.localName, attr.name)
  78. def testGetElementsByTagName(self):
  79. dom = parse(tstfile)
  80. self.confirm(dom.getElementsByTagName("LI") == \
  81. dom.documentElement.getElementsByTagName("LI"))
  82. dom.unlink()
  83. def testInsertBefore(self):
  84. dom = parseString("<doc><foo/></doc>")
  85. root = dom.documentElement
  86. elem = root.childNodes[0]
  87. nelem = dom.createElement("element")
  88. root.insertBefore(nelem, elem)
  89. self.confirm(len(root.childNodes) == 2
  90. and root.childNodes.length == 2
  91. and root.childNodes[0] is nelem
  92. and root.childNodes.item(0) is nelem
  93. and root.childNodes[1] is elem
  94. and root.childNodes.item(1) is elem
  95. and root.firstChild is nelem
  96. and root.lastChild is elem
  97. and root.toxml() == "<doc><element/><foo/></doc>"
  98. , "testInsertBefore -- node properly placed in tree")
  99. nelem = dom.createElement("element")
  100. root.insertBefore(nelem, None)
  101. self.confirm(len(root.childNodes) == 3
  102. and root.childNodes.length == 3
  103. and root.childNodes[1] is elem
  104. and root.childNodes.item(1) is elem
  105. and root.childNodes[2] is nelem
  106. and root.childNodes.item(2) is nelem
  107. and root.lastChild is nelem
  108. and nelem.previousSibling is elem
  109. and root.toxml() == "<doc><element/><foo/><element/></doc>"
  110. , "testInsertBefore -- node properly placed in tree")
  111. nelem2 = dom.createElement("bar")
  112. root.insertBefore(nelem2, nelem)
  113. self.confirm(len(root.childNodes) == 4
  114. and root.childNodes.length == 4
  115. and root.childNodes[2] is nelem2
  116. and root.childNodes.item(2) is nelem2
  117. and root.childNodes[3] is nelem
  118. and root.childNodes.item(3) is nelem
  119. and nelem2.nextSibling is nelem
  120. and nelem.previousSibling is nelem2
  121. and root.toxml() ==
  122. "<doc><element/><foo/><bar/><element/></doc>"
  123. , "testInsertBefore -- node properly placed in tree")
  124. dom.unlink()
  125. def _create_fragment_test_nodes(self):
  126. dom = parseString("<doc/>")
  127. orig = dom.createTextNode("original")
  128. c1 = dom.createTextNode("foo")
  129. c2 = dom.createTextNode("bar")
  130. c3 = dom.createTextNode("bat")
  131. dom.documentElement.appendChild(orig)
  132. frag = dom.createDocumentFragment()
  133. frag.appendChild(c1)
  134. frag.appendChild(c2)
  135. frag.appendChild(c3)
  136. return dom, orig, c1, c2, c3, frag
  137. def testInsertBeforeFragment(self):
  138. dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
  139. dom.documentElement.insertBefore(frag, None)
  140. self.confirm(tuple(dom.documentElement.childNodes) ==
  141. (orig, c1, c2, c3),
  142. "insertBefore(<fragment>, None)")
  143. frag.unlink()
  144. dom.unlink()
  145. dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
  146. dom.documentElement.insertBefore(frag, orig)
  147. self.confirm(tuple(dom.documentElement.childNodes) ==
  148. (c1, c2, c3, orig),
  149. "insertBefore(<fragment>, orig)")
  150. frag.unlink()
  151. dom.unlink()
  152. def testAppendChild(self):
  153. dom = parse(tstfile)
  154. dom.documentElement.appendChild(dom.createComment("Hello"))
  155. self.confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")
  156. self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
  157. dom.unlink()
  158. def testAppendChildFragment(self):
  159. dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
  160. dom.documentElement.appendChild(frag)
  161. self.confirm(tuple(dom.documentElement.childNodes) ==
  162. (orig, c1, c2, c3),
  163. "appendChild(<fragment>)")
  164. frag.unlink()
  165. dom.unlink()
  166. def testReplaceChildFragment(self):
  167. dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
  168. dom.documentElement.replaceChild(frag, orig)
  169. orig.unlink()
  170. self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
  171. "replaceChild(<fragment>)")
  172. frag.unlink()
  173. dom.unlink()
  174. def testLegalChildren(self):
  175. dom = Document()
  176. elem = dom.createElement('element')
  177. text = dom.createTextNode('text')
  178. self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text)
  179. dom.appendChild(elem)
  180. self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,
  181. elem)
  182. self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,
  183. elem)
  184. nodemap = elem.attributes
  185. self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,
  186. text)
  187. self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,
  188. text)
  189. elem.appendChild(text)
  190. dom.unlink()
  191. def testNamedNodeMapSetItem(self):
  192. dom = Document()
  193. elem = dom.createElement('element')
  194. attrs = elem.attributes
  195. attrs["foo"] = "bar"
  196. a = attrs.item(0)
  197. self.confirm(a.ownerDocument is dom,
  198. "NamedNodeMap.__setitem__() sets ownerDocument")
  199. self.confirm(a.ownerElement is elem,
  200. "NamedNodeMap.__setitem__() sets ownerElement")
  201. self.confirm(a.value == "bar",
  202. "NamedNodeMap.__setitem__() sets value")
  203. self.confirm(a.nodeValue == "bar",
  204. "NamedNodeMap.__setitem__() sets nodeValue")
  205. elem.unlink()
  206. dom.unlink()
  207. def testNonZero(self):
  208. dom = parse(tstfile)
  209. self.confirm(dom)# should not be zero
  210. dom.appendChild(dom.createComment("foo"))
  211. self.confirm(not dom.childNodes[-1].childNodes)
  212. dom.unlink()
  213. def testUnlink(self):
  214. dom = parse(tstfile)
  215. self.assertTrue(dom.childNodes)
  216. dom.unlink()
  217. self.assertFalse(dom.childNodes)
  218. def testContext(self):
  219. with parse(tstfile) as dom:
  220. self.assertTrue(dom.childNodes)
  221. self.assertFalse(dom.childNodes)
  222. def testElement(self):
  223. dom = Document()
  224. dom.appendChild(dom.createElement("abc"))
  225. self.confirm(dom.documentElement)
  226. dom.unlink()
  227. def testAAA(self):
  228. dom = parseString("<abc/>")
  229. el = dom.documentElement
  230. el.setAttribute("spam", "jam2")
  231. self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")
  232. a = el.getAttributeNode("spam")
  233. self.confirm(a.ownerDocument is dom,
  234. "setAttribute() sets ownerDocument")
  235. self.confirm(a.ownerElement is dom.documentElement,
  236. "setAttribute() sets ownerElement")
  237. dom.unlink()
  238. def testAAB(self):
  239. dom = parseString("<abc/>")
  240. el = dom.documentElement
  241. el.setAttribute("spam", "jam")
  242. el.setAttribute("spam", "jam2")
  243. self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")
  244. dom.unlink()
  245. def testAddAttr(self):
  246. dom = Document()
  247. child = dom.appendChild(dom.createElement("abc"))
  248. child.setAttribute("def", "ghi")
  249. self.confirm(child.getAttribute("def") == "ghi")
  250. self.confirm(child.attributes["def"].value == "ghi")
  251. child.setAttribute("jkl", "mno")
  252. self.confirm(child.getAttribute("jkl") == "mno")
  253. self.confirm(child.attributes["jkl"].value == "mno")
  254. self.confirm(len(child.attributes) == 2)
  255. child.setAttribute("def", "newval")
  256. self.confirm(child.getAttribute("def") == "newval")
  257. self.confirm(child.attributes["def"].value == "newval")
  258. self.confirm(len(child.attributes) == 2)
  259. dom.unlink()
  260. def testDeleteAttr(self):
  261. dom = Document()
  262. child = dom.appendChild(dom.createElement("abc"))
  263. self.confirm(len(child.attributes) == 0)
  264. child.setAttribute("def", "ghi")
  265. self.confirm(len(child.attributes) == 1)
  266. del child.attributes["def"]
  267. self.confirm(len(child.attributes) == 0)
  268. dom.unlink()
  269. def testRemoveAttr(self):
  270. dom = Document()
  271. child = dom.appendChild(dom.createElement("abc"))
  272. child.setAttribute("def", "ghi")
  273. self.confirm(len(child.attributes) == 1)
  274. self.assertRaises(xml.dom.NotFoundErr, child.removeAttribute, "foo")
  275. child.removeAttribute("def")
  276. self.confirm(len(child.attributes) == 0)
  277. dom.unlink()
  278. def testRemoveAttrNS(self):
  279. dom = Document()
  280. child = dom.appendChild(
  281. dom.createElementNS("http://www.python.org", "python:abc"))
  282. child.setAttributeNS("http://www.w3.org", "xmlns:python",
  283. "http://www.python.org")
  284. child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
  285. self.assertRaises(xml.dom.NotFoundErr, child.removeAttributeNS,
  286. "foo", "http://www.python.org")
  287. self.confirm(len(child.attributes) == 2)
  288. child.removeAttributeNS("http://www.python.org", "abcattr")
  289. self.confirm(len(child.attributes) == 1)
  290. dom.unlink()
  291. def testRemoveAttributeNode(self):
  292. dom = Document()
  293. child = dom.appendChild(dom.createElement("foo"))
  294. child.setAttribute("spam", "jam")
  295. self.confirm(len(child.attributes) == 1)
  296. node = child.getAttributeNode("spam")
  297. self.assertRaises(xml.dom.NotFoundErr, child.removeAttributeNode,
  298. None)
  299. self.assertIs(node, child.removeAttributeNode(node))
  300. self.confirm(len(child.attributes) == 0
  301. and child.getAttributeNode("spam") is None)
  302. dom2 = Document()
  303. child2 = dom2.appendChild(dom2.createElement("foo"))
  304. node2 = child2.getAttributeNode("spam")
  305. self.assertRaises(xml.dom.NotFoundErr, child2.removeAttributeNode,
  306. node2)
  307. dom.unlink()
  308. def testHasAttribute(self):
  309. dom = Document()
  310. child = dom.appendChild(dom.createElement("foo"))
  311. child.setAttribute("spam", "jam")
  312. self.confirm(child.hasAttribute("spam"))
  313. def testChangeAttr(self):
  314. dom = parseString("<abc/>")
  315. el = dom.documentElement
  316. el.setAttribute("spam", "jam")
  317. self.confirm(len(el.attributes) == 1)
  318. el.setAttribute("spam", "bam")
  319. # Set this attribute to be an ID and make sure that doesn't change
  320. # when changing the value:
  321. el.setIdAttribute("spam")
  322. self.confirm(len(el.attributes) == 1
  323. and el.attributes["spam"].value == "bam"
  324. and el.attributes["spam"].nodeValue == "bam"
  325. and el.getAttribute("spam") == "bam"
  326. and el.getAttributeNode("spam").isId)
  327. el.attributes["spam"] = "ham"
  328. self.confirm(len(el.attributes) == 1
  329. and el.attributes["spam"].value == "ham"
  330. and el.attributes["spam"].nodeValue == "ham"
  331. and el.getAttribute("spam") == "ham"
  332. and el.attributes["spam"].isId)
  333. el.setAttribute("spam2", "bam")
  334. self.confirm(len(el.attributes) == 2
  335. and el.attributes["spam"].value == "ham"
  336. and el.attributes["spam"].nodeValue == "ham"
  337. and el.getAttribute("spam") == "ham"
  338. and el.attributes["spam2"].value == "bam"
  339. and el.attributes["spam2"].nodeValue == "bam"
  340. and el.getAttribute("spam2") == "bam")
  341. el.attributes["spam2"] = "bam2"
  342. self.confirm(len(el.attributes) == 2
  343. and el.attributes["spam"].value == "ham"
  344. and el.attributes["spam"].nodeValue == "ham"
  345. and el.getAttribute("spam") == "ham"
  346. and el.attributes["spam2"].value == "bam2"
  347. and el.attributes["spam2"].nodeValue == "bam2"
  348. and el.getAttribute("spam2") == "bam2")
  349. dom.unlink()
  350. def testGetAttrList(self):
  351. pass
  352. def testGetAttrValues(self):
  353. pass
  354. def testGetAttrLength(self):
  355. pass
  356. def testGetAttribute(self):
  357. dom = Document()
  358. child = dom.appendChild(
  359. dom.createElementNS("http://www.python.org", "python:abc"))
  360. self.assertEqual(child.getAttribute('missing'), '')
  361. def testGetAttributeNS(self):
  362. dom = Document()
  363. child = dom.appendChild(
  364. dom.createElementNS("http://www.python.org", "python:abc"))
  365. child.setAttributeNS("http://www.w3.org", "xmlns:python",
  366. "http://www.python.org")
  367. self.assertEqual(child.getAttributeNS("http://www.w3.org", "python"),
  368. 'http://www.python.org')
  369. self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"),
  370. '')
  371. child2 = child.appendChild(dom.createElement('abc'))
  372. self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"),
  373. '')
  374. def testGetAttributeNode(self): pass
  375. def testGetElementsByTagNameNS(self):
  376. d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
  377. <minidom:myelem/>
  378. </foo>"""
  379. dom = parseString(d)
  380. elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
  381. "myelem")
  382. self.confirm(len(elems) == 1
  383. and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"
  384. and elems[0].localName == "myelem"
  385. and elems[0].prefix == "minidom"
  386. and elems[0].tagName == "minidom:myelem"
  387. and elems[0].nodeName == "minidom:myelem")
  388. dom.unlink()
  389. def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,
  390. lname):
  391. nodelist = doc.getElementsByTagNameNS(nsuri, lname)
  392. self.confirm(len(nodelist) == 0)
  393. def testGetEmptyNodeListFromElementsByTagNameNS(self):
  394. doc = parseString('<doc/>')
  395. self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
  396. doc, 'http://xml.python.org/namespaces/a', 'localname')
  397. self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
  398. doc, '*', 'splat')
  399. self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
  400. doc, 'http://xml.python.org/namespaces/a', '*')
  401. doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
  402. self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
  403. doc, "http://xml.python.org/splat", "not-there")
  404. self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
  405. doc, "*", "not-there")
  406. self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
  407. doc, "http://somewhere.else.net/not-there", "e")
  408. def testElementReprAndStr(self):
  409. dom = Document()
  410. el = dom.appendChild(dom.createElement("abc"))
  411. string1 = repr(el)
  412. string2 = str(el)
  413. self.confirm(string1 == string2)
  414. dom.unlink()
  415. def testElementReprAndStrUnicode(self):
  416. dom = Document()
  417. el = dom.appendChild(dom.createElement("abc"))
  418. string1 = repr(el)
  419. string2 = str(el)
  420. self.confirm(string1 == string2)
  421. dom.unlink()
  422. def testElementReprAndStrUnicodeNS(self):
  423. dom = Document()
  424. el = dom.appendChild(
  425. dom.createElementNS("http://www.slashdot.org", "slash:abc"))
  426. string1 = repr(el)
  427. string2 = str(el)
  428. self.confirm(string1 == string2)
  429. self.confirm("slash:abc" in string1)
  430. dom.unlink()
  431. def testAttributeRepr(self):
  432. dom = Document()
  433. el = dom.appendChild(dom.createElement("abc"))
  434. node = el.setAttribute("abc", "def")
  435. self.confirm(str(node) == repr(node))
  436. dom.unlink()
  437. def testTextNodeRepr(self): pass
  438. def testWriteXML(self):
  439. str = '<?xml version="1.0" ?><a b="c"/>'
  440. dom = parseString(str)
  441. domstr = dom.toxml()
  442. dom.unlink()
  443. self.confirm(str == domstr)
  444. def testAltNewline(self):
  445. str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
  446. dom = parseString(str)
  447. domstr = dom.toprettyxml(newl="\r\n")
  448. dom.unlink()
  449. self.confirm(domstr == str.replace("\n", "\r\n"))
  450. def test_toprettyxml_with_text_nodes(self):
  451. # see issue #4147, text nodes are not indented
  452. decl = '<?xml version="1.0" ?>\n'
  453. self.assertEqual(parseString('<B>A</B>').toprettyxml(),
  454. decl + '<B>A</B>\n')
  455. self.assertEqual(parseString('<C>A<B>A</B></C>').toprettyxml(),
  456. decl + '<C>\n\tA\n\t<B>A</B>\n</C>\n')
  457. self.assertEqual(parseString('<C><B>A</B>A</C>').toprettyxml(),
  458. decl + '<C>\n\t<B>A</B>\n\tA\n</C>\n')
  459. self.assertEqual(parseString('<C><B>A</B><B>A</B></C>').toprettyxml(),
  460. decl + '<C>\n\t<B>A</B>\n\t<B>A</B>\n</C>\n')
  461. self.assertEqual(parseString('<C><B>A</B>A<B>A</B></C>').toprettyxml(),
  462. decl + '<C>\n\t<B>A</B>\n\tA\n\t<B>A</B>\n</C>\n')
  463. def test_toprettyxml_with_adjacent_text_nodes(self):
  464. # see issue #4147, adjacent text nodes are indented normally
  465. dom = Document()
  466. elem = dom.createElement('elem')
  467. elem.appendChild(dom.createTextNode('TEXT'))
  468. elem.appendChild(dom.createTextNode('TEXT'))
  469. dom.appendChild(elem)
  470. decl = '<?xml version="1.0" ?>\n'
  471. self.assertEqual(dom.toprettyxml(),
  472. decl + '<elem>\n\tTEXT\n\tTEXT\n</elem>\n')
  473. def test_toprettyxml_preserves_content_of_text_node(self):
  474. # see issue #4147
  475. for str in ('<B>A</B>', '<A><B>C</B></A>'):
  476. dom = parseString(str)
  477. dom2 = parseString(dom.toprettyxml())
  478. self.assertEqual(
  479. dom.getElementsByTagName('B')[0].childNodes[0].toxml(),
  480. dom2.getElementsByTagName('B')[0].childNodes[0].toxml())
  481. def testProcessingInstruction(self):
  482. dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
  483. pi = dom.documentElement.firstChild
  484. self.confirm(pi.target == "mypi"
  485. and pi.data == "data \t\n "
  486. and pi.nodeName == "mypi"
  487. and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
  488. and pi.attributes is None
  489. and not pi.hasChildNodes()
  490. and len(pi.childNodes) == 0
  491. and pi.firstChild is None
  492. and pi.lastChild is None
  493. and pi.localName is None
  494. and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)
  495. def testProcessingInstructionRepr(self): pass
  496. def testTextRepr(self): pass
  497. def testWriteText(self): pass
  498. def testDocumentElement(self): pass
  499. def testTooManyDocumentElements(self):
  500. doc = parseString("<doc/>")
  501. elem = doc.createElement("extra")
  502. # Should raise an exception when adding an extra document element.
  503. self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)
  504. elem.unlink()
  505. doc.unlink()
  506. def testCreateElementNS(self): pass
  507. def testCreateAttributeNS(self): pass
  508. def testParse(self): pass
  509. def testParseString(self): pass
  510. def testComment(self): pass
  511. def testAttrListItem(self): pass
  512. def testAttrListItems(self): pass
  513. def testAttrListItemNS(self): pass
  514. def testAttrListKeys(self): pass
  515. def testAttrListKeysNS(self): pass
  516. def testRemoveNamedItem(self):
  517. doc = parseString("<doc a=''/>")
  518. e = doc.documentElement
  519. attrs = e.attributes
  520. a1 = e.getAttributeNode("a")
  521. a2 = attrs.removeNamedItem("a")
  522. self.confirm(a1.isSameNode(a2))
  523. self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")
  524. def testRemoveNamedItemNS(self):
  525. doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
  526. e = doc.documentElement
  527. attrs = e.attributes
  528. a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
  529. a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
  530. self.confirm(a1.isSameNode(a2))
  531. self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
  532. "http://xml.python.org/", "b")
  533. def testAttrListValues(self): pass
  534. def testAttrListLength(self): pass
  535. def testAttrList__getitem__(self): pass
  536. def testAttrList__setitem__(self): pass
  537. def testSetAttrValueandNodeValue(self): pass
  538. def testParseElement(self): pass
  539. def testParseAttributes(self): pass
  540. def testParseElementNamespaces(self): pass
  541. def testParseAttributeNamespaces(self): pass
  542. def testParseProcessingInstructions(self): pass
  543. def testChildNodes(self): pass
  544. def testFirstChild(self): pass
  545. def testHasChildNodes(self):
  546. dom = parseString("<doc><foo/></doc>")
  547. doc = dom.documentElement
  548. self.assertTrue(doc.hasChildNodes())
  549. dom2 = parseString("<doc/>")
  550. doc2 = dom2.documentElement
  551. self.assertFalse(doc2.hasChildNodes())
  552. def _testCloneElementCopiesAttributes(self, e1, e2, test):
  553. attrs1 = e1.attributes
  554. attrs2 = e2.attributes
  555. keys1 = list(attrs1.keys())
  556. keys2 = list(attrs2.keys())
  557. keys1.sort()
  558. keys2.sort()
  559. self.confirm(keys1 == keys2, "clone of element has same attribute keys")
  560. for i in range(len(keys1)):
  561. a1 = attrs1.item(i)
  562. a2 = attrs2.item(i)
  563. self.confirm(a1 is not a2
  564. and a1.value == a2.value
  565. and a1.nodeValue == a2.nodeValue
  566. and a1.namespaceURI == a2.namespaceURI
  567. and a1.localName == a2.localName
  568. , "clone of attribute node has proper attribute values")
  569. self.confirm(a2.ownerElement is e2,
  570. "clone of attribute node correctly owned")
  571. def _setupCloneElement(self, deep):
  572. dom = parseString("<doc attr='value'><foo/></doc>")
  573. root = dom.documentElement
  574. clone = root.cloneNode(deep)
  575. self._testCloneElementCopiesAttributes(
  576. root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
  577. # mutilate the original so shared data is detected
  578. root.tagName = root.nodeName = "MODIFIED"
  579. root.setAttribute("attr", "NEW VALUE")
  580. root.setAttribute("added", "VALUE")
  581. return dom, clone
  582. def testCloneElementShallow(self):
  583. dom, clone = self._setupCloneElement(0)
  584. self.confirm(len(clone.childNodes) == 0
  585. and clone.childNodes.length == 0
  586. and clone.parentNode is None
  587. and clone.toxml() == '<doc attr="value"/>'
  588. , "testCloneElementShallow")
  589. dom.unlink()
  590. def testCloneElementDeep(self):
  591. dom, clone = self._setupCloneElement(1)
  592. self.confirm(len(clone.childNodes) == 1
  593. and clone.childNodes.length == 1
  594. and clone.parentNode is None
  595. and clone.toxml() == '<doc attr="value"><foo/></doc>'
  596. , "testCloneElementDeep")
  597. dom.unlink()
  598. def testCloneDocumentShallow(self):
  599. doc = parseString("<?xml version='1.0'?>\n"
  600. "<!-- comment -->"
  601. "<!DOCTYPE doc [\n"
  602. "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
  603. "]>\n"
  604. "<doc attr='value'/>")
  605. doc2 = doc.cloneNode(0)
  606. self.confirm(doc2 is None,
  607. "testCloneDocumentShallow:"
  608. " shallow cloning of documents makes no sense!")
  609. def testCloneDocumentDeep(self):
  610. doc = parseString("<?xml version='1.0'?>\n"
  611. "<!-- comment -->"
  612. "<!DOCTYPE doc [\n"
  613. "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
  614. "]>\n"
  615. "<doc attr='value'/>")
  616. doc2 = doc.cloneNode(1)
  617. self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
  618. "testCloneDocumentDeep: document objects not distinct")
  619. self.confirm(len(doc.childNodes) == len(doc2.childNodes),
  620. "testCloneDocumentDeep: wrong number of Document children")
  621. self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
  622. "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
  623. self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
  624. "testCloneDocumentDeep: documentElement owner is not new document")
  625. self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),
  626. "testCloneDocumentDeep: documentElement should not be shared")
  627. if doc.doctype is not None:
  628. # check the doctype iff the original DOM maintained it
  629. self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
  630. "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
  631. self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
  632. self.confirm(not doc.doctype.isSameNode(doc2.doctype))
  633. def testCloneDocumentTypeDeepOk(self):
  634. doctype = create_nonempty_doctype()
  635. clone = doctype.cloneNode(1)
  636. self.confirm(clone is not None
  637. and clone.nodeName == doctype.nodeName
  638. and clone.name == doctype.name
  639. and clone.publicId == doctype.publicId
  640. and clone.systemId == doctype.systemId
  641. and len(clone.entities) == len(doctype.entities)
  642. and clone.entities.item(len(clone.entities)) is None
  643. and len(clone.notations) == len(doctype.notations)
  644. and clone.notations.item(len(clone.notations)) is None
  645. and len(clone.childNodes) == 0)
  646. for i in range(len(doctype.entities)):
  647. se = doctype.entities.item(i)
  648. ce = clone.entities.item(i)
  649. self.confirm((not se.isSameNode(ce))
  650. and (not ce.isSameNode(se))
  651. and ce.nodeName == se.nodeName
  652. and ce.notationName == se.notationName
  653. and ce.publicId == se.publicId
  654. and ce.systemId == se.systemId
  655. and ce.encoding == se.encoding
  656. and ce.actualEncoding == se.actualEncoding
  657. and ce.version == se.version)
  658. for i in range(len(doctype.notations)):
  659. sn = doctype.notations.item(i)
  660. cn = clone.notations.item(i)
  661. self.confirm((not sn.isSameNode(cn))
  662. and (not cn.isSameNode(sn))
  663. and cn.nodeName == sn.nodeName
  664. and cn.publicId == sn.publicId
  665. and cn.systemId == sn.systemId)
  666. def testCloneDocumentTypeDeepNotOk(self):
  667. doc = create_doc_with_doctype()
  668. clone = doc.doctype.cloneNode(1)
  669. self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
  670. def testCloneDocumentTypeShallowOk(self):
  671. doctype = create_nonempty_doctype()
  672. clone = doctype.cloneNode(0)
  673. self.confirm(clone is not None
  674. and clone.nodeName == doctype.nodeName
  675. and clone.name == doctype.name
  676. and clone.publicId == doctype.publicId
  677. and clone.systemId == doctype.systemId
  678. and len(clone.entities) == 0
  679. and clone.entities.item(0) is None
  680. and len(clone.notations) == 0
  681. and clone.notations.item(0) is None
  682. and len(clone.childNodes) == 0)
  683. def testCloneDocumentTypeShallowNotOk(self):
  684. doc = create_doc_with_doctype()
  685. clone = doc.doctype.cloneNode(0)
  686. self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
  687. def check_import_document(self, deep, testName):
  688. doc1 = parseString("<doc/>")
  689. doc2 = parseString("<doc/>")
  690. self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)
  691. def testImportDocumentShallow(self):
  692. self.check_import_document(0, "testImportDocumentShallow")
  693. def testImportDocumentDeep(self):
  694. self.check_import_document(1, "testImportDocumentDeep")
  695. def testImportDocumentTypeShallow(self):
  696. src = create_doc_with_doctype()
  697. target = create_doc_without_doctype()
  698. self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
  699. src.doctype, 0)
  700. def testImportDocumentTypeDeep(self):
  701. src = create_doc_with_doctype()
  702. target = create_doc_without_doctype()
  703. self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
  704. src.doctype, 1)
  705. # Testing attribute clones uses a helper, and should always be deep,
  706. # even if the argument to cloneNode is false.
  707. def check_clone_attribute(self, deep, testName):
  708. doc = parseString("<doc attr='value'/>")
  709. attr = doc.documentElement.getAttributeNode("attr")
  710. self.assertNotEqual(attr, None)
  711. clone = attr.cloneNode(deep)
  712. self.confirm(not clone.isSameNode(attr))
  713. self.confirm(not attr.isSameNode(clone))
  714. self.confirm(clone.ownerElement is None,
  715. testName + ": ownerElement should be None")
  716. self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
  717. testName + ": ownerDocument does not match")
  718. self.confirm(clone.specified,
  719. testName + ": cloned attribute must have specified == True")
  720. def testCloneAttributeShallow(self):
  721. self.check_clone_attribute(0, "testCloneAttributeShallow")
  722. def testCloneAttributeDeep(self):
  723. self.check_clone_attribute(1, "testCloneAttributeDeep")
  724. def check_clone_pi(self, deep, testName):
  725. doc = parseString("<?target data?><doc/>")
  726. pi = doc.firstChild
  727. self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
  728. clone = pi.cloneNode(deep)
  729. self.confirm(clone.target == pi.target
  730. and clone.data == pi.data)
  731. def testClonePIShallow(self):
  732. self.check_clone_pi(0, "testClonePIShallow")
  733. def testClonePIDeep(self):
  734. self.check_clone_pi(1, "testClonePIDeep")
  735. def check_clone_node_entity(self, clone_document):
  736. # bpo-35052: Test user data handler in cloneNode() on a document with
  737. # an entity
  738. document = xml.dom.minidom.parseString("""
  739. <?xml version="1.0" ?>
  740. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  741. "http://www.w3.org/TR/html4/strict.dtd"
  742. [ <!ENTITY smile "☺"> ]
  743. >
  744. <doc>Don't let entities make you frown &smile;</doc>
  745. """.strip())
  746. class Handler:
  747. def handle(self, operation, key, data, src, dst):
  748. self.operation = operation
  749. self.key = key
  750. self.data = data
  751. self.src = src
  752. self.dst = dst
  753. handler = Handler()
  754. doctype = document.doctype
  755. entity = doctype.entities['smile']
  756. entity.setUserData("key", "data", handler)
  757. if clone_document:
  758. # clone Document
  759. clone = document.cloneNode(deep=True)
  760. self.assertEqual(clone.documentElement.firstChild.wholeText,
  761. "Don't let entities make you frown ☺")
  762. operation = xml.dom.UserDataHandler.NODE_IMPORTED
  763. dst = clone.doctype.entities['smile']
  764. else:
  765. # clone DocumentType
  766. with support.swap_attr(doctype, 'ownerDocument', None):
  767. clone = doctype.cloneNode(deep=True)
  768. operation = xml.dom.UserDataHandler.NODE_CLONED
  769. dst = clone.entities['smile']
  770. self.assertEqual(handler.operation, operation)
  771. self.assertEqual(handler.key, "key")
  772. self.assertEqual(handler.data, "data")
  773. self.assertIs(handler.src, entity)
  774. self.assertIs(handler.dst, dst)
  775. def testCloneNodeEntity(self):
  776. self.check_clone_node_entity(False)
  777. self.check_clone_node_entity(True)
  778. def testNormalize(self):
  779. doc = parseString("<doc/>")
  780. root = doc.documentElement
  781. root.appendChild(doc.createTextNode("first"))
  782. root.appendChild(doc.createTextNode("second"))
  783. self.confirm(len(root.childNodes) == 2
  784. and root.childNodes.length == 2,
  785. "testNormalize -- preparation")
  786. doc.normalize()
  787. self.confirm(len(root.childNodes) == 1
  788. and root.childNodes.length == 1
  789. and root.firstChild is root.lastChild
  790. and root.firstChild.data == "firstsecond"
  791. , "testNormalize -- result")
  792. doc.unlink()
  793. doc = parseString("<doc/>")
  794. root = doc.documentElement
  795. root.appendChild(doc.createTextNode(""))
  796. doc.normalize()
  797. self.confirm(len(root.childNodes) == 0
  798. and root.childNodes.length == 0,
  799. "testNormalize -- single empty node removed")
  800. doc.unlink()
  801. def testNormalizeCombineAndNextSibling(self):
  802. doc = parseString("<doc/>")
  803. root = doc.documentElement
  804. root.appendChild(doc.createTextNode("first"))
  805. root.appendChild(doc.createTextNode("second"))
  806. root.appendChild(doc.createElement("i"))
  807. self.confirm(len(root.childNodes) == 3
  808. and root.childNodes.length == 3,
  809. "testNormalizeCombineAndNextSibling -- preparation")
  810. doc.normalize()
  811. self.confirm(len(root.childNodes) == 2
  812. and root.childNodes.length == 2
  813. and root.firstChild.data == "firstsecond"
  814. and root.firstChild is not root.lastChild
  815. and root.firstChild.nextSibling is root.lastChild
  816. and root.firstChild.previousSibling is None
  817. and root.lastChild.previousSibling is root.firstChild
  818. and root.lastChild.nextSibling is None
  819. , "testNormalizeCombinedAndNextSibling -- result")
  820. doc.unlink()
  821. def testNormalizeDeleteWithPrevSibling(self):
  822. doc = parseString("<doc/>")
  823. root = doc.documentElement
  824. root.appendChild(doc.createTextNode("first"))
  825. root.appendChild(doc.createTextNode(""))
  826. self.confirm(len(root.childNodes) == 2
  827. and root.childNodes.length == 2,
  828. "testNormalizeDeleteWithPrevSibling -- preparation")
  829. doc.normalize()
  830. self.confirm(len(root.childNodes) == 1
  831. and root.childNodes.length == 1
  832. and root.firstChild.data == "first"
  833. and root.firstChild is root.lastChild
  834. and root.firstChild.nextSibling is None
  835. and root.firstChild.previousSibling is None
  836. , "testNormalizeDeleteWithPrevSibling -- result")
  837. doc.unlink()
  838. def testNormalizeDeleteWithNextSibling(self):
  839. doc = parseString("<doc/>")
  840. root = doc.documentElement
  841. root.appendChild(doc.createTextNode(""))
  842. root.appendChild(doc.createTextNode("second"))
  843. self.confirm(len(root.childNodes) == 2
  844. and root.childNodes.length == 2,
  845. "testNormalizeDeleteWithNextSibling -- preparation")
  846. doc.normalize()
  847. self.confirm(len(root.childNodes) == 1
  848. and root.childNodes.length == 1
  849. and root.firstChild.data == "second"
  850. and root.firstChild is root.lastChild
  851. and root.firstChild.nextSibling is None
  852. and root.firstChild.previousSibling is None
  853. , "testNormalizeDeleteWithNextSibling -- result")
  854. doc.unlink()
  855. def testNormalizeDeleteWithTwoNonTextSiblings(self):
  856. doc = parseString("<doc/>")
  857. root = doc.documentElement
  858. root.appendChild(doc.createElement("i"))
  859. root.appendChild(doc.createTextNode(""))
  860. root.appendChild(doc.createElement("i"))
  861. self.confirm(len(root.childNodes) == 3
  862. and root.childNodes.length == 3,
  863. "testNormalizeDeleteWithTwoSiblings -- preparation")
  864. doc.normalize()
  865. self.confirm(len(root.childNodes) == 2
  866. and root.childNodes.length == 2
  867. and root.firstChild is not root.lastChild
  868. and root.firstChild.nextSibling is root.lastChild
  869. and root.firstChild.previousSibling is None
  870. and root.lastChild.previousSibling is root.firstChild
  871. and root.lastChild.nextSibling is None
  872. , "testNormalizeDeleteWithTwoSiblings -- result")
  873. doc.unlink()
  874. def testNormalizeDeleteAndCombine(self):
  875. doc = parseString("<doc/>")
  876. root = doc.documentElement
  877. root.appendChild(doc.createTextNode(""))
  878. root.appendChild(doc.createTextNode("second"))
  879. root.appendChild(doc.createTextNode(""))
  880. root.appendChild(doc.createTextNode("fourth"))
  881. root.appendChild(doc.createTextNode(""))
  882. self.confirm(len(root.childNodes) == 5
  883. and root.childNodes.length == 5,
  884. "testNormalizeDeleteAndCombine -- preparation")
  885. doc.normalize()
  886. self.confirm(len(root.childNodes) == 1
  887. and root.childNodes.length == 1
  888. and root.firstChild is root.lastChild
  889. and root.firstChild.data == "secondfourth"
  890. and root.firstChild.previousSibling is None
  891. and root.firstChild.nextSibling is None
  892. , "testNormalizeDeleteAndCombine -- result")
  893. doc.unlink()
  894. def testNormalizeRecursion(self):
  895. doc = parseString("<doc>"
  896. "<o>"
  897. "<i/>"
  898. "t"
  899. #
  900. #x
  901. "</o>"
  902. "<o>"
  903. "<o>"
  904. "t2"
  905. #x2
  906. "</o>"
  907. "t3"
  908. #x3
  909. "</o>"
  910. #
  911. "</doc>")
  912. root = doc.documentElement
  913. root.childNodes[0].appendChild(doc.createTextNode(""))
  914. root.childNodes[0].appendChild(doc.createTextNode("x"))
  915. root.childNodes[1].childNodes[0].appendChild(doc.createTextNode("x2"))
  916. root.childNodes[1].appendChild(doc.createTextNode("x3"))
  917. root.appendChild(doc.createTextNode(""))
  918. self.confirm(len(root.childNodes) == 3
  919. and root.childNodes.length == 3
  920. and len(root.childNodes[0].childNodes) == 4
  921. and root.childNodes[0].childNodes.length == 4
  922. and len(root.childNodes[1].childNodes) == 3
  923. and root.childNodes[1].childNodes.length == 3
  924. and len(root.childNodes[1].childNodes[0].childNodes) == 2
  925. and root.childNodes[1].childNodes[0].childNodes.length == 2
  926. , "testNormalize2 -- preparation")
  927. doc.normalize()
  928. self.confirm(len(root.childNodes) == 2
  929. and root.childNodes.length == 2
  930. and len(root.childNodes[0].childNodes) == 2
  931. and root.childNodes[0].childNodes.length == 2
  932. and len(root.childNodes[1].childNodes) == 2
  933. and root.childNodes[1].childNodes.length == 2
  934. and len(root.childNodes[1].childNodes[0].childNodes) == 1
  935. and root.childNodes[1].childNodes[0].childNodes.length == 1
  936. , "testNormalize2 -- childNodes lengths")
  937. self.confirm(root.childNodes[0].childNodes[1].data == "tx"
  938. and root.childNodes[1].childNodes[0].childNodes[0].data == "t2x2"
  939. and root.childNodes[1].childNodes[1].data == "t3x3"
  940. , "testNormalize2 -- joined text fields")
  941. self.confirm(root.childNodes[0].childNodes[1].nextSibling is None
  942. and root.childNodes[0].childNodes[1].previousSibling
  943. is root.childNodes[0].childNodes[0]
  944. and root.childNodes[0].childNodes[0].previousSibling is None
  945. and root.childNodes[0].childNodes[0].nextSibling
  946. is root.childNodes[0].childNodes[1]
  947. and root.childNodes[1].childNodes[1].nextSibling is None
  948. and root.childNodes[1].childNodes[1].previousSibling
  949. is root.childNodes[1].childNodes[0]
  950. and root.childNodes[1].childNodes[0].previousSibling is None
  951. and root.childNodes[1].childNodes[0].nextSibling
  952. is root.childNodes[1].childNodes[1]
  953. , "testNormalize2 -- sibling pointers")
  954. doc.unlink()
  955. def testBug0777884(self):
  956. doc = parseString("<o>text</o>")
  957. text = doc.documentElement.childNodes[0]
  958. self.assertEqual(text.nodeType, Node.TEXT_NODE)
  959. # Should run quietly, doing nothing.
  960. text.normalize()
  961. doc.unlink()
  962. def testBug1433694(self):
  963. doc = parseString("<o><i/>t</o>")
  964. node = doc.documentElement
  965. node.childNodes[1].nodeValue = ""
  966. node.normalize()
  967. self.confirm(node.childNodes[-1].nextSibling is None,
  968. "Final child's .nextSibling should be None")
  969. def testSiblings(self):
  970. doc = parseString("<doc><?pi?>text?<elm/></doc>")
  971. root = doc.documentElement
  972. (pi, text, elm) = root.childNodes
  973. self.confirm(pi.nextSibling is text and
  974. pi.previousSibling is None and
  975. text.nextSibling is elm and
  976. text.previousSibling is pi and
  977. elm.nextSibling is None and
  978. elm.previousSibling is text, "testSiblings")
  979. doc.unlink()
  980. def testParents(self):
  981. doc = parseString(
  982. "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
  983. root = doc.documentElement
  984. elm1 = root.childNodes[0]
  985. (elm2a, elm2b) = elm1.childNodes
  986. elm3 = elm2b.childNodes[0]
  987. self.confirm(root.parentNode is doc and
  988. elm1.parentNode is root and
  989. elm2a.parentNode is elm1 and
  990. elm2b.parentNode is elm1 and
  991. elm3.parentNode is elm2b, "testParents")
  992. doc.unlink()
  993. def testNodeListItem(self):
  994. doc = parseString("<doc><e/><e/></doc>")
  995. children = doc.childNodes
  996. docelem = children[0]
  997. self.confirm(children[0] is children.item(0)
  998. and children.item(1) is None
  999. and docelem.childNodes.item(0) is docelem.childNodes[0]
  1000. and docelem.childNodes.item(1) is docelem.childNodes[1]
  1001. and docelem.childNodes.item(0).childNodes.item(0) is None,
  1002. "test NodeList.item()")
  1003. doc.unlink()
  1004. def testEncodings(self):
  1005. doc = parseString('<foo>&#x20ac;</foo>')
  1006. self.assertEqual(doc.toxml(),
  1007. '<?xml version="1.0" ?><foo>\u20ac</foo>')
  1008. self.assertEqual(doc.toxml('utf-8'),
  1009. b'<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>')
  1010. self.assertEqual(doc.toxml('iso-8859-15'),
  1011. b'<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>')
  1012. self.assertEqual(doc.toxml('us-ascii'),
  1013. b'<?xml version="1.0" encoding="us-ascii"?><foo>&#8364;</foo>')
  1014. self.assertEqual(doc.toxml('utf-16'),
  1015. '<?xml version="1.0" encoding="utf-16"?>'
  1016. '<foo>\u20ac</foo>'.encode('utf-16'))
  1017. # Verify that character decoding errors raise exceptions instead
  1018. # of crashing
  1019. if pyexpat.version_info >= (2, 4, 5):
  1020. self.assertRaises(ExpatError, parseString,
  1021. b'<fran\xe7ais></fran\xe7ais>')
  1022. self.assertRaises(ExpatError, parseString,
  1023. b'<franais>Comment \xe7a va ? Tr\xe8s bien ?</franais>')
  1024. else:
  1025. self.assertRaises(UnicodeDecodeError, parseString,
  1026. b'<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
  1027. doc.unlink()
  1028. def testStandalone(self):
  1029. doc = parseString('<foo>&#x20ac;</foo>')
  1030. self.assertEqual(doc.toxml(),
  1031. '<?xml version="1.0" ?><foo>\u20ac</foo>')
  1032. self.assertEqual(doc.toxml(standalone=None),
  1033. '<?xml version="1.0" ?><foo>\u20ac</foo>')
  1034. self.assertEqual(doc.toxml(standalone=True),
  1035. '<?xml version="1.0" standalone="yes"?><foo>\u20ac</foo>')
  1036. self.assertEqual(doc.toxml(standalone=False),
  1037. '<?xml version="1.0" standalone="no"?><foo>\u20ac</foo>')
  1038. self.assertEqual(doc.toxml('utf-8', True),
  1039. b'<?xml version="1.0" encoding="utf-8" standalone="yes"?>'
  1040. b'<foo>\xe2\x82\xac</foo>')
  1041. doc.unlink()
  1042. class UserDataHandler:
  1043. called = 0
  1044. def handle(self, operation, key, data, src, dst):
  1045. dst.setUserData(key, data + 1, self)
  1046. src.setUserData(key, None, None)
  1047. self.called = 1
  1048. def testUserData(self):
  1049. dom = Document()
  1050. n = dom.createElement('e')
  1051. self.confirm(n.getUserData("foo") is None)
  1052. n.setUserData("foo", None, None)
  1053. self.confirm(n.getUserData("foo") is None)
  1054. n.setUserData("foo", 12, 12)
  1055. n.setUserData("bar", 13, 13)
  1056. self.confirm(n.getUserData("foo") == 12)
  1057. self.confirm(n.getUserData("bar") == 13)
  1058. n.setUserData("foo", None, None)
  1059. self.confirm(n.getUserData("foo") is None)
  1060. self.confirm(n.getUserData("bar") == 13)
  1061. handler = self.UserDataHandler()
  1062. n.setUserData("bar", 12, handler)
  1063. c = n.cloneNode(1)
  1064. self.confirm(handler.called
  1065. and n.getUserData("bar") is None
  1066. and c.getUserData("bar") == 13)
  1067. n.unlink()
  1068. c.unlink()
  1069. dom.unlink()
  1070. def checkRenameNodeSharedConstraints(self, doc, node):
  1071. # Make sure illegal NS usage is detected:
  1072. self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
  1073. "http://xml.python.org/ns", "xmlns:foo")
  1074. doc2 = parseString("<doc/>")
  1075. self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
  1076. xml.dom.EMPTY_NAMESPACE, "foo")
  1077. def testRenameAttribute(self):
  1078. doc = parseString("<doc a='v'/>")
  1079. elem = doc.documentElement
  1080. attrmap = elem.attributes
  1081. attr = elem.attributes['a']
  1082. # Simple renaming
  1083. attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
  1084. self.confirm(attr.name == "b"
  1085. and attr.nodeName == "b"
  1086. and attr.localName is None
  1087. and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
  1088. and attr.prefix is None
  1089. and attr.value == "v"
  1090. and elem.getAttributeNode("a") is None
  1091. and elem.getAttributeNode("b").isSameNode(attr)
  1092. and attrmap["b"].isSameNode(attr)
  1093. and attr.ownerDocument.isSameNode(doc)
  1094. and attr.ownerElement.isSameNode(elem))
  1095. # Rename to have a namespace, no prefix
  1096. attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
  1097. self.confirm(attr.name == "c"
  1098. and attr.nodeName == "c"
  1099. and attr.localName == "c"
  1100. and attr.namespaceURI == "http://xml.python.org/ns"
  1101. and attr.prefix is None
  1102. and attr.value == "v"
  1103. and elem.getAttributeNode("a") is None
  1104. and elem.getAttributeNode("b") is None
  1105. and elem.getAttributeNode("c").isSameNode(attr)
  1106. and elem.getAttributeNodeNS(
  1107. "http://xml.python.org/ns", "c").isSameNode(attr)
  1108. and attrmap["c"].isSameNode(attr)
  1109. and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
  1110. # Rename to have a namespace, with prefix
  1111. attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
  1112. self.confirm(attr.name == "p:d"
  1113. and attr.nodeName == "p:d"
  1114. and attr.localName == "d"
  1115. and attr.namespaceURI == "http://xml.python.org/ns2"
  1116. and attr.prefix == "p"
  1117. and attr.value == "v"
  1118. and elem.getAttributeNode("a") is None
  1119. and elem.getAttributeNode("b") is None
  1120. and elem.getAttributeNode("c") is None
  1121. and elem.getAttributeNodeNS(
  1122. "http://xml.python.org/ns", "c") is None
  1123. and elem.getAttributeNode("p:d").isSameNode(attr)
  1124. and elem.getAttributeNodeNS(
  1125. "http://xml.python.org/ns2", "d").isSameNode(attr)
  1126. and attrmap["p:d"].isSameNode(attr)
  1127. and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
  1128. # Rename back to a simple non-NS node
  1129. attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
  1130. self.confirm(attr.name == "e"
  1131. and attr.nodeName == "e"
  1132. and attr.localName is None
  1133. and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
  1134. and attr.prefix is None
  1135. and attr.value == "v"
  1136. and elem.getAttributeNode("a") is None
  1137. and elem.getAttributeNode("b") is None
  1138. and elem.getAttributeNode("c") is None
  1139. and elem.getAttributeNode("p:d") is None
  1140. and elem.getAttributeNodeNS(
  1141. "http://xml.python.org/ns", "c") is None
  1142. and elem.getAttributeNode("e").isSameNode(attr)
  1143. and attrmap["e"].isSameNode(attr))
  1144. self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
  1145. "http://xml.python.org/ns", "xmlns")
  1146. self.checkRenameNodeSharedConstraints(doc, attr)
  1147. doc.unlink()
  1148. def testRenameElement(self):
  1149. doc = parseString("<doc/>")
  1150. elem = doc.documentElement
  1151. # Simple renaming
  1152. elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
  1153. self.confirm(elem.tagName == "a"
  1154. and elem.nodeName == "a"
  1155. and elem.localName is None
  1156. and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
  1157. and elem.prefix is None
  1158. and elem.ownerDocument.isSameNode(doc))
  1159. # Rename to have a namespace, no prefix
  1160. elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
  1161. self.confirm(elem.tagName == "b"
  1162. and elem.nodeName == "b"
  1163. and elem.localName == "b"
  1164. and elem.namespaceURI == "http://xml.python.org/ns"
  1165. and elem.prefix is None
  1166. and elem.ownerDocument.isSameNode(doc))
  1167. # Rename to have a namespace, with prefix
  1168. elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
  1169. self.confirm(elem.tagName == "p:c"
  1170. and elem.nodeName == "p:c"
  1171. and elem.localName == "c"
  1172. and elem.namespaceURI == "http://xml.python.org/ns2"
  1173. and elem.prefix == "p"
  1174. and elem.ownerDocument.isSameNode(doc))
  1175. # Rename back to a simple non-NS node
  1176. elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
  1177. self.confirm(elem.tagName == "d"
  1178. and elem.nodeName == "d"
  1179. and elem.localName is None
  1180. and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
  1181. and elem.prefix is None
  1182. and elem.ownerDocument.isSameNode(doc))
  1183. self.checkRenameNodeSharedConstraints(doc, elem)
  1184. doc.unlink()
  1185. def testRenameOther(self):
  1186. # We have to create a comment node explicitly since not all DOM
  1187. # builders used with minidom add comments to the DOM.
  1188. doc = xml.dom.minidom.getDOMImplementation().createDocument(
  1189. xml.dom.EMPTY_NAMESPACE, "e", None)
  1190. node = doc.createComment("comment")
  1191. self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
  1192. xml.dom.EMPTY_NAMESPACE, "foo")
  1193. doc.unlink()
  1194. def testWholeText(self):
  1195. doc = parseString("<doc>a</doc>")
  1196. elem = doc.documentElement
  1197. text = elem.childNodes[0]
  1198. self.assertEqual(text.nodeType, Node.TEXT_NODE)
  1199. self.checkWholeText(text, "a")
  1200. elem.appendChild(doc.createTextNode("b"))
  1201. self.checkWholeText(text, "ab")
  1202. elem.insertBefore(doc.createCDATASection("c"), text)
  1203. self.checkWholeText(text, "cab")
  1204. # make sure we don't cross other nodes
  1205. splitter = doc.createComment("comment")
  1206. elem.appendChild(splitter)
  1207. text2 = doc.createTextNode("d")
  1208. elem.appendChild(text2)
  1209. self.checkWholeText(text, "cab")
  1210. self.checkWholeText(text2, "d")
  1211. x = doc.createElement("x")
  1212. elem.replaceChild(x, splitter)
  1213. splitter = x
  1214. self.checkWholeText(text, "cab")
  1215. self.checkWholeText(text2, "d")
  1216. x = doc.createProcessingInstruction("y", "z")
  1217. elem.replaceChild(x, splitter)
  1218. splitter = x
  1219. self.checkWholeText(text, "cab")
  1220. self.checkWholeText(text2, "d")
  1221. elem.removeChild(splitter)
  1222. self.checkWholeText(text, "cabd")
  1223. self.checkWholeText(text2, "cabd")
  1224. def testPatch1094164(self):
  1225. doc = parseString("<doc><e/></doc>")
  1226. elem = doc.documentElement
  1227. e = elem.firstChild
  1228. self.confirm(e.parentNode is elem, "Before replaceChild()")
  1229. # Check that replacing a child with itself leaves the tree unchanged
  1230. elem.replaceChild(e, e)
  1231. self.confirm(e.parentNode is elem, "After replaceChild()")
  1232. def testReplaceWholeText(self):
  1233. def setup():
  1234. doc = parseString("<doc>a<e/>d</doc>")
  1235. elem = doc.documentElement
  1236. text1 = elem.firstChild
  1237. text2 = elem.lastChild
  1238. splitter = text1.nextSibling
  1239. elem.insertBefore(doc.createTextNode("b"), splitter)
  1240. elem.insertBefore(doc.createCDATASection("c"), text1)
  1241. return doc, elem, text1, splitter, text2
  1242. doc, elem, text1, splitter, text2 = setup()
  1243. text = text1.replaceWholeText("new content")
  1244. self.checkWholeText(text, "new content")
  1245. self.checkWholeText(text2, "d")
  1246. self.confirm(len(elem.childNodes) == 3)
  1247. doc, elem, text1, splitter, text2 = setup()
  1248. text = text2.replaceWholeText("new content")
  1249. self.checkWholeText(text, "new content")
  1250. self.checkWholeText(text1, "cab")
  1251. self.confirm(len(elem.childNodes) == 5)
  1252. doc, elem, text1, splitter, text2 = setup()
  1253. text = text1.replaceWholeText("")
  1254. self.checkWholeText(text2, "d")
  1255. self.confirm(text is None
  1256. and len(elem.childNodes) == 2)
  1257. def testSchemaType(self):
  1258. doc = parseString(
  1259. "<!DOCTYPE doc [\n"
  1260. " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
  1261. " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
  1262. " <!ATTLIST doc id ID #IMPLIED \n"
  1263. " ref IDREF #IMPLIED \n"
  1264. " refs IDREFS #IMPLIED \n"
  1265. " enum (a|b) #IMPLIED \n"
  1266. " ent ENTITY #IMPLIED \n"
  1267. " ents ENTITIES #IMPLIED \n"
  1268. " nm NMTOKEN #IMPLIED \n"
  1269. " nms NMTOKENS #IMPLIED \n"
  1270. " text CDATA #IMPLIED \n"
  1271. " >\n"
  1272. "]><doc id='name' notid='name' text='splat!' enum='b'"
  1273. " ref='name' refs='name name' ent='e1' ents='e1 e2'"
  1274. " nm='123' nms='123 abc' />")
  1275. elem = doc.documentElement
  1276. # We don't want to rely on any specific loader at this point, so
  1277. # just make sure we can get to all the names, and that the
  1278. # DTD-based namespace is right. The names can vary by loader
  1279. # since each supports a different level of DTD information.
  1280. t = elem.schemaType
  1281. self.confirm(t.name is None
  1282. and t.namespace == xml.dom.EMPTY_NAMESPACE)
  1283. names = "id notid text enum ref refs ent ents nm nms".split()
  1284. for name in names:
  1285. a = elem.getAttributeNode(name)
  1286. t = a.schemaType
  1287. self.confirm(hasattr(t, "name")
  1288. and t.namespace == xml.dom.EMPTY_NAMESPACE)
  1289. def testSetIdAttribute(self):
  1290. doc = parseString("<doc a1='v' a2='w'/>")
  1291. e = doc.documentElement
  1292. a1 = e.getAttributeNode("a1")
  1293. a2 = e.getAttributeNode("a2")
  1294. self.confirm(doc.getElementById("v") is None
  1295. and not a1.isId
  1296. and not a2.isId)
  1297. e.setIdAttribute("a1")
  1298. self.confirm(e.isSameNode(doc.getElementById("v"))
  1299. and a1.isId
  1300. and not a2.isId)
  1301. e.setIdAttribute("a2")
  1302. self.confirm(e.isSameNode(doc.getElementById("v"))
  1303. and e.isSameNode(doc.getElementById("w"))
  1304. and a1.isId
  1305. and a2.isId)
  1306. # replace the a1 node; the new node should *not* be an ID
  1307. a3 = doc.createAttribute("a1")
  1308. a3.value = "v"
  1309. e.setAttributeNode(a3)
  1310. self.confirm(doc.getElementById("v") is None
  1311. and e.isSameNode(doc.getElementById("w"))
  1312. and not a1.isId
  1313. and a2.isId
  1314. and not a3.isId)
  1315. # renaming an attribute should not affect its ID-ness:
  1316. doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
  1317. self.confirm(e.isSameNode(doc.getElementById("w"))
  1318. and a2.isId)
  1319. def testSetIdAttributeNS(self):
  1320. NS1 = "http://xml.python.org/ns1"
  1321. NS2 = "http://xml.python.org/ns2"
  1322. doc = parseString("<doc"
  1323. " xmlns:ns1='" + NS1 + "'"
  1324. " xmlns:ns2='" + NS2 + "'"
  1325. " ns1:a1='v' ns2:a2='w'/>")
  1326. e = doc.documentElement
  1327. a1 = e.getAttributeNodeNS(NS1, "a1")
  1328. a2 = e.getAttributeNodeNS(NS2, "a2")
  1329. self.confirm(doc.getElementById("v") is None
  1330. and not a1.isId
  1331. and not a2.isId)
  1332. e.setIdAttributeNS(NS1, "a1")
  1333. self.confirm(e.isSameNode(doc.getElementById("v"))
  1334. and a1.isId
  1335. and not a2.isId)
  1336. e.setIdAttributeNS(NS2, "a2")
  1337. self.confirm(e.isSameNode(doc.getElementById("v"))
  1338. and e.isSameNode(doc.getElementById("w"))
  1339. and a1.isId
  1340. and a2.isId)
  1341. # replace the a1 node; the new node should *not* be an ID
  1342. a3 = doc.createAttributeNS(NS1, "a1")
  1343. a3.value = "v"
  1344. e.setAttributeNode(a3)
  1345. self.confirm(e.isSameNode(doc.getElementById("w")))
  1346. self.confirm(not a1.isId)
  1347. self.confirm(a2.isId)
  1348. self.confirm(not a3.isId)
  1349. self.confirm(doc.getElementById("v") is None)
  1350. # renaming an attribute should not affect its ID-ness:
  1351. doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
  1352. self.confirm(e.isSameNode(doc.getElementById("w"))
  1353. and a2.isId)
  1354. def testSetIdAttributeNode(self):
  1355. NS1 = "http://xml.python.org/ns1"
  1356. NS2 = "http://xml.python.org/ns2"
  1357. doc = parseString("<doc"
  1358. " xmlns:ns1='" + NS1 + "'"
  1359. " xmlns:ns2='" + NS2 + "'"
  1360. " ns1:a1='v' ns2:a2='w'/>")
  1361. e = doc.documentElement
  1362. a1 = e.getAttributeNodeNS(NS1, "a1")
  1363. a2 = e.getAttributeNodeNS(NS2, "a2")
  1364. self.confirm(doc.getElementById("v") is None
  1365. and not a1.isId
  1366. and not a2.isId)
  1367. e.setIdAttributeNode(a1)
  1368. self.confirm(e.isSameNode(doc.getElementById("v"))
  1369. and a1.isId
  1370. and not a2.isId)
  1371. e.setIdAttributeNode(a2)
  1372. self.confirm(e.isSameNode(doc.getElementById("v"))
  1373. and e.isSameNode(doc.getElementById("w"))
  1374. and a1.isId
  1375. and a2.isId)
  1376. # replace the a1 node; the new node should *not* be an ID
  1377. a3 = doc.createAttributeNS(NS1, "a1")
  1378. a3.value = "v"
  1379. e.setAttributeNode(a3)
  1380. self.confirm(e.isSameNode(doc.getElementById("w")))
  1381. self.confirm(not a1.isId)
  1382. self.confirm(a2.isId)
  1383. self.confirm(not a3.isId)
  1384. self.confirm(doc.getElementById("v") is None)
  1385. # renaming an attribute should not affect its ID-ness:
  1386. doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
  1387. self.confirm(e.isSameNode(doc.getElementById("w"))
  1388. and a2.isId)
  1389. def assert_recursive_equal(self, doc, doc2):
  1390. stack = [(doc, doc2)]
  1391. while stack:
  1392. n1, n2 = stack.pop()
  1393. self.assertEqual(n1.nodeType, n2.nodeType)
  1394. self.assertEqual(len(n1.childNodes), len(n2.childNodes))
  1395. self.assertEqual(n1.nodeName, n2.nodeName)
  1396. self.assertFalse(n1.isSameNode(n2))
  1397. self.assertFalse(n2.isSameNode(n1))
  1398. if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
  1399. len(n1.entities)
  1400. len(n2.entities)
  1401. len(n1.notations)
  1402. len(n2.notations)
  1403. self.assertEqual(len(n1.entities), len(n2.entities))
  1404. self.assertEqual(len(n1.notations), len(n2.notations))
  1405. for i in range(len(n1.notations)):
  1406. # XXX this loop body doesn't seem to be executed?
  1407. no1 = n1.notations.item(i)
  1408. no2 = n1.notations.item(i)
  1409. self.assertEqual(no1.name, no2.name)
  1410. self.assertEqual(no1.publicId, no2.publicId)
  1411. self.assertEqual(no1.systemId, no2.systemId)
  1412. stack.append((no1, no2))
  1413. for i in range(len(n1.entities)):
  1414. e1 = n1.entities.item(i)
  1415. e2 = n2.entities.item(i)
  1416. self.assertEqual(e1.notationName, e2.notationName)
  1417. self.assertEqual(e1.publicId, e2.publicId)
  1418. self.assertEqual(e1.systemId, e2.systemId)
  1419. stack.append((e1, e2))
  1420. if n1.nodeType != Node.DOCUMENT_NODE:
  1421. self.assertTrue(n1.ownerDocument.isSameNode(doc))
  1422. self.assertTrue(n2.ownerDocument.isSameNode(doc2))
  1423. for i in range(len(n1.childNodes)):
  1424. stack.append((n1.childNodes[i], n2.childNodes[i]))
  1425. def testPickledDocument(self):
  1426. doc = parseString(sample)
  1427. for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
  1428. s = pickle.dumps(doc, proto)
  1429. doc2 = pickle.loads(s)
  1430. self.assert_recursive_equal(doc, doc2)
  1431. def testDeepcopiedDocument(self):
  1432. doc = parseString(sample)
  1433. doc2 = copy.deepcopy(doc)
  1434. self.assert_recursive_equal(doc, doc2)
  1435. def testSerializeCommentNodeWithDoubleHyphen(self):
  1436. doc = create_doc_without_doctype()
  1437. doc.appendChild(doc.createComment("foo--bar"))
  1438. self.assertRaises(ValueError, doc.toxml)
  1439. def testEmptyXMLNSValue(self):
  1440. doc = parseString("<element xmlns=''>\n"
  1441. "<foo/>\n</element>")
  1442. doc2 = parseString(doc.toxml())
  1443. self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
  1444. def testExceptionOnSpacesInXMLNSValue(self):
  1445. if pyexpat.version_info >= (2, 4, 5):
  1446. context = self.assertRaisesRegex(ExpatError, 'syntax error')
  1447. else:
  1448. context = self.assertRaisesRegex(ValueError, 'Unsupported syntax')
  1449. with context:
  1450. parseString('<element xmlns:abc="http:abc.com/de f g/hi/j k"><abc:foo /></element>')
  1451. def testDocRemoveChild(self):
  1452. doc = parse(tstfile)
  1453. title_tag = doc.documentElement.getElementsByTagName("TITLE")[0]
  1454. self.assertRaises( xml.dom.NotFoundErr, doc.removeChild, title_tag)
  1455. num_children_before = len(doc.childNodes)
  1456. doc.removeChild(doc.childNodes[0])
  1457. num_children_after = len(doc.childNodes)
  1458. self.assertTrue(num_children_after == num_children_before - 1)
  1459. def testProcessingInstructionNameError(self):
  1460. # wrong variable in .nodeValue property will
  1461. # lead to "NameError: name 'data' is not defined"
  1462. doc = parse(tstfile)
  1463. pi = doc.createProcessingInstruction("y", "z")
  1464. pi.nodeValue = "crash"
  1465. def test_minidom_attribute_order(self):
  1466. xml_str = '<?xml version="1.0" ?><curriculum status="public" company="example"/>'
  1467. doc = parseString(xml_str)
  1468. output = io.StringIO()
  1469. doc.writexml(output)
  1470. self.assertEqual(output.getvalue(), xml_str)
  1471. def test_toxml_with_attributes_ordered(self):
  1472. xml_str = '<?xml version="1.0" ?><curriculum status="public" company="example"/>'
  1473. doc = parseString(xml_str)
  1474. self.assertEqual(doc.toxml(), xml_str)
  1475. def test_toprettyxml_with_attributes_ordered(self):
  1476. xml_str = '<?xml version="1.0" ?><curriculum status="public" company="example"/>'
  1477. doc = parseString(xml_str)
  1478. self.assertEqual(doc.toprettyxml(),
  1479. '<?xml version="1.0" ?>\n'
  1480. '<curriculum status="public" company="example"/>\n')
  1481. def test_toprettyxml_with_cdata(self):
  1482. xml_str = '<?xml version="1.0" ?><root><node><![CDATA[</data>]]></node></root>'
  1483. doc = parseString(xml_str)
  1484. self.assertEqual(doc.toprettyxml(),
  1485. '<?xml version="1.0" ?>\n'
  1486. '<root>\n'
  1487. '\t<node><![CDATA[</data>]]></node>\n'
  1488. '</root>\n')
  1489. def test_cdata_parsing(self):
  1490. xml_str = '<?xml version="1.0" ?><root><node><![CDATA[</data>]]></node></root>'
  1491. dom1 = parseString(xml_str)
  1492. self.checkWholeText(dom1.getElementsByTagName('node')[0].firstChild, '</data>')
  1493. dom2 = parseString(dom1.toprettyxml())
  1494. self.checkWholeText(dom2.getElementsByTagName('node')[0].firstChild, '</data>')
  1495. if __name__ == "__main__":
  1496. unittest.main()