| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694 |
- # test for xml.dom.minidom
- import copy
- import pickle
- import io
- from test import support
- import unittest
- import pyexpat
- import xml.dom.minidom
- from xml.dom.minidom import parse, Attr, Node, Document, parseString
- from xml.dom.minidom import getDOMImplementation
- from xml.parsers.expat import ExpatError
- tstfile = support.findfile("test.xml", subdir="xmltestdata")
- sample = ("<?xml version='1.0' encoding='us-ascii'?>\n"
- "<!DOCTYPE doc PUBLIC 'http://xml.python.org/public'"
- " 'http://xml.python.org/system' [\n"
- " <!ELEMENT e EMPTY>\n"
- " <!ENTITY ent SYSTEM 'http://xml.python.org/entity'>\n"
- "]><doc attr='value'> text\n"
- "<?pi sample?> <!-- comment --> <e/> </doc>")
- # The tests of DocumentType importing use these helpers to construct
- # the documents to work with, since not all DOM builders actually
- # create the DocumentType nodes.
- def create_doc_without_doctype(doctype=None):
- return getDOMImplementation().createDocument(None, "doc", doctype)
- def create_nonempty_doctype():
- doctype = getDOMImplementation().createDocumentType("doc", None, None)
- doctype.entities._seq = []
- doctype.notations._seq = []
- notation = xml.dom.minidom.Notation("my-notation", None,
- "http://xml.python.org/notations/my")
- doctype.notations._seq.append(notation)
- entity = xml.dom.minidom.Entity("my-entity", None,
- "http://xml.python.org/entities/my",
- "my-notation")
- entity.version = "1.0"
- entity.encoding = "utf-8"
- entity.actualEncoding = "us-ascii"
- doctype.entities._seq.append(entity)
- return doctype
- def create_doc_with_doctype():
- doctype = create_nonempty_doctype()
- doc = create_doc_without_doctype(doctype)
- doctype.entities.item(0).ownerDocument = doc
- doctype.notations.item(0).ownerDocument = doc
- return doc
- class MinidomTest(unittest.TestCase):
- def confirm(self, test, testname = "Test"):
- self.assertTrue(test, testname)
- def checkWholeText(self, node, s):
- t = node.wholeText
- self.confirm(t == s, "looking for %r, found %r" % (s, t))
- def testDocumentAsyncAttr(self):
- doc = Document()
- self.assertFalse(doc.async_)
- self.assertFalse(Document.async_)
- def testParseFromBinaryFile(self):
- with open(tstfile, 'rb') as file:
- dom = parse(file)
- dom.unlink()
- self.confirm(isinstance(dom, Document))
- def testParseFromTextFile(self):
- with open(tstfile, 'r', encoding='iso-8859-1') as file:
- dom = parse(file)
- dom.unlink()
- self.confirm(isinstance(dom, Document))
- def testAttrModeSetsParamsAsAttrs(self):
- attr = Attr("qName", "namespaceURI", "localName", "prefix")
- self.assertEqual(attr.name, "qName")
- self.assertEqual(attr.namespaceURI, "namespaceURI")
- self.assertEqual(attr.prefix, "prefix")
- self.assertEqual(attr.localName, "localName")
- def testAttrModeSetsNonOptionalAttrs(self):
- attr = Attr("qName", "namespaceURI", None, "prefix")
- self.assertEqual(attr.name, "qName")
- self.assertEqual(attr.namespaceURI, "namespaceURI")
- self.assertEqual(attr.prefix, "prefix")
- self.assertEqual(attr.localName, attr.name)
- def testGetElementsByTagName(self):
- dom = parse(tstfile)
- self.confirm(dom.getElementsByTagName("LI") == \
- dom.documentElement.getElementsByTagName("LI"))
- dom.unlink()
- def testInsertBefore(self):
- dom = parseString("<doc><foo/></doc>")
- root = dom.documentElement
- elem = root.childNodes[0]
- nelem = dom.createElement("element")
- root.insertBefore(nelem, elem)
- self.confirm(len(root.childNodes) == 2
- and root.childNodes.length == 2
- and root.childNodes[0] is nelem
- and root.childNodes.item(0) is nelem
- and root.childNodes[1] is elem
- and root.childNodes.item(1) is elem
- and root.firstChild is nelem
- and root.lastChild is elem
- and root.toxml() == "<doc><element/><foo/></doc>"
- , "testInsertBefore -- node properly placed in tree")
- nelem = dom.createElement("element")
- root.insertBefore(nelem, None)
- self.confirm(len(root.childNodes) == 3
- and root.childNodes.length == 3
- and root.childNodes[1] is elem
- and root.childNodes.item(1) is elem
- and root.childNodes[2] is nelem
- and root.childNodes.item(2) is nelem
- and root.lastChild is nelem
- and nelem.previousSibling is elem
- and root.toxml() == "<doc><element/><foo/><element/></doc>"
- , "testInsertBefore -- node properly placed in tree")
- nelem2 = dom.createElement("bar")
- root.insertBefore(nelem2, nelem)
- self.confirm(len(root.childNodes) == 4
- and root.childNodes.length == 4
- and root.childNodes[2] is nelem2
- and root.childNodes.item(2) is nelem2
- and root.childNodes[3] is nelem
- and root.childNodes.item(3) is nelem
- and nelem2.nextSibling is nelem
- and nelem.previousSibling is nelem2
- and root.toxml() ==
- "<doc><element/><foo/><bar/><element/></doc>"
- , "testInsertBefore -- node properly placed in tree")
- dom.unlink()
- def _create_fragment_test_nodes(self):
- dom = parseString("<doc/>")
- orig = dom.createTextNode("original")
- c1 = dom.createTextNode("foo")
- c2 = dom.createTextNode("bar")
- c3 = dom.createTextNode("bat")
- dom.documentElement.appendChild(orig)
- frag = dom.createDocumentFragment()
- frag.appendChild(c1)
- frag.appendChild(c2)
- frag.appendChild(c3)
- return dom, orig, c1, c2, c3, frag
- def testInsertBeforeFragment(self):
- dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
- dom.documentElement.insertBefore(frag, None)
- self.confirm(tuple(dom.documentElement.childNodes) ==
- (orig, c1, c2, c3),
- "insertBefore(<fragment>, None)")
- frag.unlink()
- dom.unlink()
- dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
- dom.documentElement.insertBefore(frag, orig)
- self.confirm(tuple(dom.documentElement.childNodes) ==
- (c1, c2, c3, orig),
- "insertBefore(<fragment>, orig)")
- frag.unlink()
- dom.unlink()
- def testAppendChild(self):
- dom = parse(tstfile)
- dom.documentElement.appendChild(dom.createComment("Hello"))
- self.confirm(dom.documentElement.childNodes[-1].nodeName == "#comment")
- self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
- dom.unlink()
- def testAppendChildFragment(self):
- dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
- dom.documentElement.appendChild(frag)
- self.confirm(tuple(dom.documentElement.childNodes) ==
- (orig, c1, c2, c3),
- "appendChild(<fragment>)")
- frag.unlink()
- dom.unlink()
- def testReplaceChildFragment(self):
- dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
- dom.documentElement.replaceChild(frag, orig)
- orig.unlink()
- self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3),
- "replaceChild(<fragment>)")
- frag.unlink()
- dom.unlink()
- def testLegalChildren(self):
- dom = Document()
- elem = dom.createElement('element')
- text = dom.createTextNode('text')
- self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text)
- dom.appendChild(elem)
- self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text,
- elem)
- self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text,
- elem)
- nodemap = elem.attributes
- self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem,
- text)
- self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS,
- text)
- elem.appendChild(text)
- dom.unlink()
- def testNamedNodeMapSetItem(self):
- dom = Document()
- elem = dom.createElement('element')
- attrs = elem.attributes
- attrs["foo"] = "bar"
- a = attrs.item(0)
- self.confirm(a.ownerDocument is dom,
- "NamedNodeMap.__setitem__() sets ownerDocument")
- self.confirm(a.ownerElement is elem,
- "NamedNodeMap.__setitem__() sets ownerElement")
- self.confirm(a.value == "bar",
- "NamedNodeMap.__setitem__() sets value")
- self.confirm(a.nodeValue == "bar",
- "NamedNodeMap.__setitem__() sets nodeValue")
- elem.unlink()
- dom.unlink()
- def testNonZero(self):
- dom = parse(tstfile)
- self.confirm(dom)# should not be zero
- dom.appendChild(dom.createComment("foo"))
- self.confirm(not dom.childNodes[-1].childNodes)
- dom.unlink()
- def testUnlink(self):
- dom = parse(tstfile)
- self.assertTrue(dom.childNodes)
- dom.unlink()
- self.assertFalse(dom.childNodes)
- def testContext(self):
- with parse(tstfile) as dom:
- self.assertTrue(dom.childNodes)
- self.assertFalse(dom.childNodes)
- def testElement(self):
- dom = Document()
- dom.appendChild(dom.createElement("abc"))
- self.confirm(dom.documentElement)
- dom.unlink()
- def testAAA(self):
- dom = parseString("<abc/>")
- el = dom.documentElement
- el.setAttribute("spam", "jam2")
- self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAA")
- a = el.getAttributeNode("spam")
- self.confirm(a.ownerDocument is dom,
- "setAttribute() sets ownerDocument")
- self.confirm(a.ownerElement is dom.documentElement,
- "setAttribute() sets ownerElement")
- dom.unlink()
- def testAAB(self):
- dom = parseString("<abc/>")
- el = dom.documentElement
- el.setAttribute("spam", "jam")
- el.setAttribute("spam", "jam2")
- self.confirm(el.toxml() == '<abc spam="jam2"/>', "testAAB")
- dom.unlink()
- def testAddAttr(self):
- dom = Document()
- child = dom.appendChild(dom.createElement("abc"))
- child.setAttribute("def", "ghi")
- self.confirm(child.getAttribute("def") == "ghi")
- self.confirm(child.attributes["def"].value == "ghi")
- child.setAttribute("jkl", "mno")
- self.confirm(child.getAttribute("jkl") == "mno")
- self.confirm(child.attributes["jkl"].value == "mno")
- self.confirm(len(child.attributes) == 2)
- child.setAttribute("def", "newval")
- self.confirm(child.getAttribute("def") == "newval")
- self.confirm(child.attributes["def"].value == "newval")
- self.confirm(len(child.attributes) == 2)
- dom.unlink()
- def testDeleteAttr(self):
- dom = Document()
- child = dom.appendChild(dom.createElement("abc"))
- self.confirm(len(child.attributes) == 0)
- child.setAttribute("def", "ghi")
- self.confirm(len(child.attributes) == 1)
- del child.attributes["def"]
- self.confirm(len(child.attributes) == 0)
- dom.unlink()
- def testRemoveAttr(self):
- dom = Document()
- child = dom.appendChild(dom.createElement("abc"))
- child.setAttribute("def", "ghi")
- self.confirm(len(child.attributes) == 1)
- self.assertRaises(xml.dom.NotFoundErr, child.removeAttribute, "foo")
- child.removeAttribute("def")
- self.confirm(len(child.attributes) == 0)
- dom.unlink()
- def testRemoveAttrNS(self):
- dom = Document()
- child = dom.appendChild(
- dom.createElementNS("http://www.python.org", "python:abc"))
- child.setAttributeNS("http://www.w3.org", "xmlns:python",
- "http://www.python.org")
- child.setAttributeNS("http://www.python.org", "python:abcattr", "foo")
- self.assertRaises(xml.dom.NotFoundErr, child.removeAttributeNS,
- "foo", "http://www.python.org")
- self.confirm(len(child.attributes) == 2)
- child.removeAttributeNS("http://www.python.org", "abcattr")
- self.confirm(len(child.attributes) == 1)
- dom.unlink()
- def testRemoveAttributeNode(self):
- dom = Document()
- child = dom.appendChild(dom.createElement("foo"))
- child.setAttribute("spam", "jam")
- self.confirm(len(child.attributes) == 1)
- node = child.getAttributeNode("spam")
- self.assertRaises(xml.dom.NotFoundErr, child.removeAttributeNode,
- None)
- self.assertIs(node, child.removeAttributeNode(node))
- self.confirm(len(child.attributes) == 0
- and child.getAttributeNode("spam") is None)
- dom2 = Document()
- child2 = dom2.appendChild(dom2.createElement("foo"))
- node2 = child2.getAttributeNode("spam")
- self.assertRaises(xml.dom.NotFoundErr, child2.removeAttributeNode,
- node2)
- dom.unlink()
- def testHasAttribute(self):
- dom = Document()
- child = dom.appendChild(dom.createElement("foo"))
- child.setAttribute("spam", "jam")
- self.confirm(child.hasAttribute("spam"))
- def testChangeAttr(self):
- dom = parseString("<abc/>")
- el = dom.documentElement
- el.setAttribute("spam", "jam")
- self.confirm(len(el.attributes) == 1)
- el.setAttribute("spam", "bam")
- # Set this attribute to be an ID and make sure that doesn't change
- # when changing the value:
- el.setIdAttribute("spam")
- self.confirm(len(el.attributes) == 1
- and el.attributes["spam"].value == "bam"
- and el.attributes["spam"].nodeValue == "bam"
- and el.getAttribute("spam") == "bam"
- and el.getAttributeNode("spam").isId)
- el.attributes["spam"] = "ham"
- self.confirm(len(el.attributes) == 1
- and el.attributes["spam"].value == "ham"
- and el.attributes["spam"].nodeValue == "ham"
- and el.getAttribute("spam") == "ham"
- and el.attributes["spam"].isId)
- el.setAttribute("spam2", "bam")
- self.confirm(len(el.attributes) == 2
- and el.attributes["spam"].value == "ham"
- and el.attributes["spam"].nodeValue == "ham"
- and el.getAttribute("spam") == "ham"
- and el.attributes["spam2"].value == "bam"
- and el.attributes["spam2"].nodeValue == "bam"
- and el.getAttribute("spam2") == "bam")
- el.attributes["spam2"] = "bam2"
- self.confirm(len(el.attributes) == 2
- and el.attributes["spam"].value == "ham"
- and el.attributes["spam"].nodeValue == "ham"
- and el.getAttribute("spam") == "ham"
- and el.attributes["spam2"].value == "bam2"
- and el.attributes["spam2"].nodeValue == "bam2"
- and el.getAttribute("spam2") == "bam2")
- dom.unlink()
- def testGetAttrList(self):
- pass
- def testGetAttrValues(self):
- pass
- def testGetAttrLength(self):
- pass
- def testGetAttribute(self):
- dom = Document()
- child = dom.appendChild(
- dom.createElementNS("http://www.python.org", "python:abc"))
- self.assertEqual(child.getAttribute('missing'), '')
- def testGetAttributeNS(self):
- dom = Document()
- child = dom.appendChild(
- dom.createElementNS("http://www.python.org", "python:abc"))
- child.setAttributeNS("http://www.w3.org", "xmlns:python",
- "http://www.python.org")
- self.assertEqual(child.getAttributeNS("http://www.w3.org", "python"),
- 'http://www.python.org')
- self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"),
- '')
- child2 = child.appendChild(dom.createElement('abc'))
- self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"),
- '')
- def testGetAttributeNode(self): pass
- def testGetElementsByTagNameNS(self):
- d="""<foo xmlns:minidom='http://pyxml.sf.net/minidom'>
- <minidom:myelem/>
- </foo>"""
- dom = parseString(d)
- elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom",
- "myelem")
- self.confirm(len(elems) == 1
- and elems[0].namespaceURI == "http://pyxml.sf.net/minidom"
- and elems[0].localName == "myelem"
- and elems[0].prefix == "minidom"
- and elems[0].tagName == "minidom:myelem"
- and elems[0].nodeName == "minidom:myelem")
- dom.unlink()
- def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri,
- lname):
- nodelist = doc.getElementsByTagNameNS(nsuri, lname)
- self.confirm(len(nodelist) == 0)
- def testGetEmptyNodeListFromElementsByTagNameNS(self):
- doc = parseString('<doc/>')
- self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
- doc, 'http://xml.python.org/namespaces/a', 'localname')
- self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
- doc, '*', 'splat')
- self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
- doc, 'http://xml.python.org/namespaces/a', '*')
- doc = parseString('<doc xmlns="http://xml.python.org/splat"><e/></doc>')
- self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
- doc, "http://xml.python.org/splat", "not-there")
- self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
- doc, "*", "not-there")
- self.get_empty_nodelist_from_elements_by_tagName_ns_helper(
- doc, "http://somewhere.else.net/not-there", "e")
- def testElementReprAndStr(self):
- dom = Document()
- el = dom.appendChild(dom.createElement("abc"))
- string1 = repr(el)
- string2 = str(el)
- self.confirm(string1 == string2)
- dom.unlink()
- def testElementReprAndStrUnicode(self):
- dom = Document()
- el = dom.appendChild(dom.createElement("abc"))
- string1 = repr(el)
- string2 = str(el)
- self.confirm(string1 == string2)
- dom.unlink()
- def testElementReprAndStrUnicodeNS(self):
- dom = Document()
- el = dom.appendChild(
- dom.createElementNS("http://www.slashdot.org", "slash:abc"))
- string1 = repr(el)
- string2 = str(el)
- self.confirm(string1 == string2)
- self.confirm("slash:abc" in string1)
- dom.unlink()
- def testAttributeRepr(self):
- dom = Document()
- el = dom.appendChild(dom.createElement("abc"))
- node = el.setAttribute("abc", "def")
- self.confirm(str(node) == repr(node))
- dom.unlink()
- def testTextNodeRepr(self): pass
- def testWriteXML(self):
- str = '<?xml version="1.0" ?><a b="c"/>'
- dom = parseString(str)
- domstr = dom.toxml()
- dom.unlink()
- self.confirm(str == domstr)
- def testAltNewline(self):
- str = '<?xml version="1.0" ?>\n<a b="c"/>\n'
- dom = parseString(str)
- domstr = dom.toprettyxml(newl="\r\n")
- dom.unlink()
- self.confirm(domstr == str.replace("\n", "\r\n"))
- def test_toprettyxml_with_text_nodes(self):
- # see issue #4147, text nodes are not indented
- decl = '<?xml version="1.0" ?>\n'
- self.assertEqual(parseString('<B>A</B>').toprettyxml(),
- decl + '<B>A</B>\n')
- self.assertEqual(parseString('<C>A<B>A</B></C>').toprettyxml(),
- decl + '<C>\n\tA\n\t<B>A</B>\n</C>\n')
- self.assertEqual(parseString('<C><B>A</B>A</C>').toprettyxml(),
- decl + '<C>\n\t<B>A</B>\n\tA\n</C>\n')
- self.assertEqual(parseString('<C><B>A</B><B>A</B></C>').toprettyxml(),
- decl + '<C>\n\t<B>A</B>\n\t<B>A</B>\n</C>\n')
- self.assertEqual(parseString('<C><B>A</B>A<B>A</B></C>').toprettyxml(),
- decl + '<C>\n\t<B>A</B>\n\tA\n\t<B>A</B>\n</C>\n')
- def test_toprettyxml_with_adjacent_text_nodes(self):
- # see issue #4147, adjacent text nodes are indented normally
- dom = Document()
- elem = dom.createElement('elem')
- elem.appendChild(dom.createTextNode('TEXT'))
- elem.appendChild(dom.createTextNode('TEXT'))
- dom.appendChild(elem)
- decl = '<?xml version="1.0" ?>\n'
- self.assertEqual(dom.toprettyxml(),
- decl + '<elem>\n\tTEXT\n\tTEXT\n</elem>\n')
- def test_toprettyxml_preserves_content_of_text_node(self):
- # see issue #4147
- for str in ('<B>A</B>', '<A><B>C</B></A>'):
- dom = parseString(str)
- dom2 = parseString(dom.toprettyxml())
- self.assertEqual(
- dom.getElementsByTagName('B')[0].childNodes[0].toxml(),
- dom2.getElementsByTagName('B')[0].childNodes[0].toxml())
- def testProcessingInstruction(self):
- dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
- pi = dom.documentElement.firstChild
- self.confirm(pi.target == "mypi"
- and pi.data == "data \t\n "
- and pi.nodeName == "mypi"
- and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE
- and pi.attributes is None
- and not pi.hasChildNodes()
- and len(pi.childNodes) == 0
- and pi.firstChild is None
- and pi.lastChild is None
- and pi.localName is None
- and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE)
- def testProcessingInstructionRepr(self): pass
- def testTextRepr(self): pass
- def testWriteText(self): pass
- def testDocumentElement(self): pass
- def testTooManyDocumentElements(self):
- doc = parseString("<doc/>")
- elem = doc.createElement("extra")
- # Should raise an exception when adding an extra document element.
- self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem)
- elem.unlink()
- doc.unlink()
- def testCreateElementNS(self): pass
- def testCreateAttributeNS(self): pass
- def testParse(self): pass
- def testParseString(self): pass
- def testComment(self): pass
- def testAttrListItem(self): pass
- def testAttrListItems(self): pass
- def testAttrListItemNS(self): pass
- def testAttrListKeys(self): pass
- def testAttrListKeysNS(self): pass
- def testRemoveNamedItem(self):
- doc = parseString("<doc a=''/>")
- e = doc.documentElement
- attrs = e.attributes
- a1 = e.getAttributeNode("a")
- a2 = attrs.removeNamedItem("a")
- self.confirm(a1.isSameNode(a2))
- self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a")
- def testRemoveNamedItemNS(self):
- doc = parseString("<doc xmlns:a='http://xml.python.org/' a:b=''/>")
- e = doc.documentElement
- attrs = e.attributes
- a1 = e.getAttributeNodeNS("http://xml.python.org/", "b")
- a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b")
- self.confirm(a1.isSameNode(a2))
- self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS,
- "http://xml.python.org/", "b")
- def testAttrListValues(self): pass
- def testAttrListLength(self): pass
- def testAttrList__getitem__(self): pass
- def testAttrList__setitem__(self): pass
- def testSetAttrValueandNodeValue(self): pass
- def testParseElement(self): pass
- def testParseAttributes(self): pass
- def testParseElementNamespaces(self): pass
- def testParseAttributeNamespaces(self): pass
- def testParseProcessingInstructions(self): pass
- def testChildNodes(self): pass
- def testFirstChild(self): pass
- def testHasChildNodes(self):
- dom = parseString("<doc><foo/></doc>")
- doc = dom.documentElement
- self.assertTrue(doc.hasChildNodes())
- dom2 = parseString("<doc/>")
- doc2 = dom2.documentElement
- self.assertFalse(doc2.hasChildNodes())
- def _testCloneElementCopiesAttributes(self, e1, e2, test):
- attrs1 = e1.attributes
- attrs2 = e2.attributes
- keys1 = list(attrs1.keys())
- keys2 = list(attrs2.keys())
- keys1.sort()
- keys2.sort()
- self.confirm(keys1 == keys2, "clone of element has same attribute keys")
- for i in range(len(keys1)):
- a1 = attrs1.item(i)
- a2 = attrs2.item(i)
- self.confirm(a1 is not a2
- and a1.value == a2.value
- and a1.nodeValue == a2.nodeValue
- and a1.namespaceURI == a2.namespaceURI
- and a1.localName == a2.localName
- , "clone of attribute node has proper attribute values")
- self.confirm(a2.ownerElement is e2,
- "clone of attribute node correctly owned")
- def _setupCloneElement(self, deep):
- dom = parseString("<doc attr='value'><foo/></doc>")
- root = dom.documentElement
- clone = root.cloneNode(deep)
- self._testCloneElementCopiesAttributes(
- root, clone, "testCloneElement" + (deep and "Deep" or "Shallow"))
- # mutilate the original so shared data is detected
- root.tagName = root.nodeName = "MODIFIED"
- root.setAttribute("attr", "NEW VALUE")
- root.setAttribute("added", "VALUE")
- return dom, clone
- def testCloneElementShallow(self):
- dom, clone = self._setupCloneElement(0)
- self.confirm(len(clone.childNodes) == 0
- and clone.childNodes.length == 0
- and clone.parentNode is None
- and clone.toxml() == '<doc attr="value"/>'
- , "testCloneElementShallow")
- dom.unlink()
- def testCloneElementDeep(self):
- dom, clone = self._setupCloneElement(1)
- self.confirm(len(clone.childNodes) == 1
- and clone.childNodes.length == 1
- and clone.parentNode is None
- and clone.toxml() == '<doc attr="value"><foo/></doc>'
- , "testCloneElementDeep")
- dom.unlink()
- def testCloneDocumentShallow(self):
- doc = parseString("<?xml version='1.0'?>\n"
- "<!-- comment -->"
- "<!DOCTYPE doc [\n"
- "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
- "]>\n"
- "<doc attr='value'/>")
- doc2 = doc.cloneNode(0)
- self.confirm(doc2 is None,
- "testCloneDocumentShallow:"
- " shallow cloning of documents makes no sense!")
- def testCloneDocumentDeep(self):
- doc = parseString("<?xml version='1.0'?>\n"
- "<!-- comment -->"
- "<!DOCTYPE doc [\n"
- "<!NOTATION notation SYSTEM 'http://xml.python.org/'>\n"
- "]>\n"
- "<doc attr='value'/>")
- doc2 = doc.cloneNode(1)
- self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)),
- "testCloneDocumentDeep: document objects not distinct")
- self.confirm(len(doc.childNodes) == len(doc2.childNodes),
- "testCloneDocumentDeep: wrong number of Document children")
- self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE,
- "testCloneDocumentDeep: documentElement not an ELEMENT_NODE")
- self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2),
- "testCloneDocumentDeep: documentElement owner is not new document")
- self.confirm(not doc.documentElement.isSameNode(doc2.documentElement),
- "testCloneDocumentDeep: documentElement should not be shared")
- if doc.doctype is not None:
- # check the doctype iff the original DOM maintained it
- self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE,
- "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE")
- self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2))
- self.confirm(not doc.doctype.isSameNode(doc2.doctype))
- def testCloneDocumentTypeDeepOk(self):
- doctype = create_nonempty_doctype()
- clone = doctype.cloneNode(1)
- self.confirm(clone is not None
- and clone.nodeName == doctype.nodeName
- and clone.name == doctype.name
- and clone.publicId == doctype.publicId
- and clone.systemId == doctype.systemId
- and len(clone.entities) == len(doctype.entities)
- and clone.entities.item(len(clone.entities)) is None
- and len(clone.notations) == len(doctype.notations)
- and clone.notations.item(len(clone.notations)) is None
- and len(clone.childNodes) == 0)
- for i in range(len(doctype.entities)):
- se = doctype.entities.item(i)
- ce = clone.entities.item(i)
- self.confirm((not se.isSameNode(ce))
- and (not ce.isSameNode(se))
- and ce.nodeName == se.nodeName
- and ce.notationName == se.notationName
- and ce.publicId == se.publicId
- and ce.systemId == se.systemId
- and ce.encoding == se.encoding
- and ce.actualEncoding == se.actualEncoding
- and ce.version == se.version)
- for i in range(len(doctype.notations)):
- sn = doctype.notations.item(i)
- cn = clone.notations.item(i)
- self.confirm((not sn.isSameNode(cn))
- and (not cn.isSameNode(sn))
- and cn.nodeName == sn.nodeName
- and cn.publicId == sn.publicId
- and cn.systemId == sn.systemId)
- def testCloneDocumentTypeDeepNotOk(self):
- doc = create_doc_with_doctype()
- clone = doc.doctype.cloneNode(1)
- self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk")
- def testCloneDocumentTypeShallowOk(self):
- doctype = create_nonempty_doctype()
- clone = doctype.cloneNode(0)
- self.confirm(clone is not None
- and clone.nodeName == doctype.nodeName
- and clone.name == doctype.name
- and clone.publicId == doctype.publicId
- and clone.systemId == doctype.systemId
- and len(clone.entities) == 0
- and clone.entities.item(0) is None
- and len(clone.notations) == 0
- and clone.notations.item(0) is None
- and len(clone.childNodes) == 0)
- def testCloneDocumentTypeShallowNotOk(self):
- doc = create_doc_with_doctype()
- clone = doc.doctype.cloneNode(0)
- self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk")
- def check_import_document(self, deep, testName):
- doc1 = parseString("<doc/>")
- doc2 = parseString("<doc/>")
- self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep)
- def testImportDocumentShallow(self):
- self.check_import_document(0, "testImportDocumentShallow")
- def testImportDocumentDeep(self):
- self.check_import_document(1, "testImportDocumentDeep")
- def testImportDocumentTypeShallow(self):
- src = create_doc_with_doctype()
- target = create_doc_without_doctype()
- self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
- src.doctype, 0)
- def testImportDocumentTypeDeep(self):
- src = create_doc_with_doctype()
- target = create_doc_without_doctype()
- self.assertRaises(xml.dom.NotSupportedErr, target.importNode,
- src.doctype, 1)
- # Testing attribute clones uses a helper, and should always be deep,
- # even if the argument to cloneNode is false.
- def check_clone_attribute(self, deep, testName):
- doc = parseString("<doc attr='value'/>")
- attr = doc.documentElement.getAttributeNode("attr")
- self.assertNotEqual(attr, None)
- clone = attr.cloneNode(deep)
- self.confirm(not clone.isSameNode(attr))
- self.confirm(not attr.isSameNode(clone))
- self.confirm(clone.ownerElement is None,
- testName + ": ownerElement should be None")
- self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument),
- testName + ": ownerDocument does not match")
- self.confirm(clone.specified,
- testName + ": cloned attribute must have specified == True")
- def testCloneAttributeShallow(self):
- self.check_clone_attribute(0, "testCloneAttributeShallow")
- def testCloneAttributeDeep(self):
- self.check_clone_attribute(1, "testCloneAttributeDeep")
- def check_clone_pi(self, deep, testName):
- doc = parseString("<?target data?><doc/>")
- pi = doc.firstChild
- self.assertEqual(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE)
- clone = pi.cloneNode(deep)
- self.confirm(clone.target == pi.target
- and clone.data == pi.data)
- def testClonePIShallow(self):
- self.check_clone_pi(0, "testClonePIShallow")
- def testClonePIDeep(self):
- self.check_clone_pi(1, "testClonePIDeep")
- def check_clone_node_entity(self, clone_document):
- # bpo-35052: Test user data handler in cloneNode() on a document with
- # an entity
- document = xml.dom.minidom.parseString("""
- <?xml version="1.0" ?>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd"
- [ <!ENTITY smile "☺"> ]
- >
- <doc>Don't let entities make you frown ⌣</doc>
- """.strip())
- class Handler:
- def handle(self, operation, key, data, src, dst):
- self.operation = operation
- self.key = key
- self.data = data
- self.src = src
- self.dst = dst
- handler = Handler()
- doctype = document.doctype
- entity = doctype.entities['smile']
- entity.setUserData("key", "data", handler)
- if clone_document:
- # clone Document
- clone = document.cloneNode(deep=True)
- self.assertEqual(clone.documentElement.firstChild.wholeText,
- "Don't let entities make you frown ☺")
- operation = xml.dom.UserDataHandler.NODE_IMPORTED
- dst = clone.doctype.entities['smile']
- else:
- # clone DocumentType
- with support.swap_attr(doctype, 'ownerDocument', None):
- clone = doctype.cloneNode(deep=True)
- operation = xml.dom.UserDataHandler.NODE_CLONED
- dst = clone.entities['smile']
- self.assertEqual(handler.operation, operation)
- self.assertEqual(handler.key, "key")
- self.assertEqual(handler.data, "data")
- self.assertIs(handler.src, entity)
- self.assertIs(handler.dst, dst)
- def testCloneNodeEntity(self):
- self.check_clone_node_entity(False)
- self.check_clone_node_entity(True)
- def testNormalize(self):
- doc = parseString("<doc/>")
- root = doc.documentElement
- root.appendChild(doc.createTextNode("first"))
- root.appendChild(doc.createTextNode("second"))
- self.confirm(len(root.childNodes) == 2
- and root.childNodes.length == 2,
- "testNormalize -- preparation")
- doc.normalize()
- self.confirm(len(root.childNodes) == 1
- and root.childNodes.length == 1
- and root.firstChild is root.lastChild
- and root.firstChild.data == "firstsecond"
- , "testNormalize -- result")
- doc.unlink()
- doc = parseString("<doc/>")
- root = doc.documentElement
- root.appendChild(doc.createTextNode(""))
- doc.normalize()
- self.confirm(len(root.childNodes) == 0
- and root.childNodes.length == 0,
- "testNormalize -- single empty node removed")
- doc.unlink()
- def testNormalizeCombineAndNextSibling(self):
- doc = parseString("<doc/>")
- root = doc.documentElement
- root.appendChild(doc.createTextNode("first"))
- root.appendChild(doc.createTextNode("second"))
- root.appendChild(doc.createElement("i"))
- self.confirm(len(root.childNodes) == 3
- and root.childNodes.length == 3,
- "testNormalizeCombineAndNextSibling -- preparation")
- doc.normalize()
- self.confirm(len(root.childNodes) == 2
- and root.childNodes.length == 2
- and root.firstChild.data == "firstsecond"
- and root.firstChild is not root.lastChild
- and root.firstChild.nextSibling is root.lastChild
- and root.firstChild.previousSibling is None
- and root.lastChild.previousSibling is root.firstChild
- and root.lastChild.nextSibling is None
- , "testNormalizeCombinedAndNextSibling -- result")
- doc.unlink()
- def testNormalizeDeleteWithPrevSibling(self):
- doc = parseString("<doc/>")
- root = doc.documentElement
- root.appendChild(doc.createTextNode("first"))
- root.appendChild(doc.createTextNode(""))
- self.confirm(len(root.childNodes) == 2
- and root.childNodes.length == 2,
- "testNormalizeDeleteWithPrevSibling -- preparation")
- doc.normalize()
- self.confirm(len(root.childNodes) == 1
- and root.childNodes.length == 1
- and root.firstChild.data == "first"
- and root.firstChild is root.lastChild
- and root.firstChild.nextSibling is None
- and root.firstChild.previousSibling is None
- , "testNormalizeDeleteWithPrevSibling -- result")
- doc.unlink()
- def testNormalizeDeleteWithNextSibling(self):
- doc = parseString("<doc/>")
- root = doc.documentElement
- root.appendChild(doc.createTextNode(""))
- root.appendChild(doc.createTextNode("second"))
- self.confirm(len(root.childNodes) == 2
- and root.childNodes.length == 2,
- "testNormalizeDeleteWithNextSibling -- preparation")
- doc.normalize()
- self.confirm(len(root.childNodes) == 1
- and root.childNodes.length == 1
- and root.firstChild.data == "second"
- and root.firstChild is root.lastChild
- and root.firstChild.nextSibling is None
- and root.firstChild.previousSibling is None
- , "testNormalizeDeleteWithNextSibling -- result")
- doc.unlink()
- def testNormalizeDeleteWithTwoNonTextSiblings(self):
- doc = parseString("<doc/>")
- root = doc.documentElement
- root.appendChild(doc.createElement("i"))
- root.appendChild(doc.createTextNode(""))
- root.appendChild(doc.createElement("i"))
- self.confirm(len(root.childNodes) == 3
- and root.childNodes.length == 3,
- "testNormalizeDeleteWithTwoSiblings -- preparation")
- doc.normalize()
- self.confirm(len(root.childNodes) == 2
- and root.childNodes.length == 2
- and root.firstChild is not root.lastChild
- and root.firstChild.nextSibling is root.lastChild
- and root.firstChild.previousSibling is None
- and root.lastChild.previousSibling is root.firstChild
- and root.lastChild.nextSibling is None
- , "testNormalizeDeleteWithTwoSiblings -- result")
- doc.unlink()
- def testNormalizeDeleteAndCombine(self):
- doc = parseString("<doc/>")
- root = doc.documentElement
- root.appendChild(doc.createTextNode(""))
- root.appendChild(doc.createTextNode("second"))
- root.appendChild(doc.createTextNode(""))
- root.appendChild(doc.createTextNode("fourth"))
- root.appendChild(doc.createTextNode(""))
- self.confirm(len(root.childNodes) == 5
- and root.childNodes.length == 5,
- "testNormalizeDeleteAndCombine -- preparation")
- doc.normalize()
- self.confirm(len(root.childNodes) == 1
- and root.childNodes.length == 1
- and root.firstChild is root.lastChild
- and root.firstChild.data == "secondfourth"
- and root.firstChild.previousSibling is None
- and root.firstChild.nextSibling is None
- , "testNormalizeDeleteAndCombine -- result")
- doc.unlink()
- def testNormalizeRecursion(self):
- doc = parseString("<doc>"
- "<o>"
- "<i/>"
- "t"
- #
- #x
- "</o>"
- "<o>"
- "<o>"
- "t2"
- #x2
- "</o>"
- "t3"
- #x3
- "</o>"
- #
- "</doc>")
- root = doc.documentElement
- root.childNodes[0].appendChild(doc.createTextNode(""))
- root.childNodes[0].appendChild(doc.createTextNode("x"))
- root.childNodes[1].childNodes[0].appendChild(doc.createTextNode("x2"))
- root.childNodes[1].appendChild(doc.createTextNode("x3"))
- root.appendChild(doc.createTextNode(""))
- self.confirm(len(root.childNodes) == 3
- and root.childNodes.length == 3
- and len(root.childNodes[0].childNodes) == 4
- and root.childNodes[0].childNodes.length == 4
- and len(root.childNodes[1].childNodes) == 3
- and root.childNodes[1].childNodes.length == 3
- and len(root.childNodes[1].childNodes[0].childNodes) == 2
- and root.childNodes[1].childNodes[0].childNodes.length == 2
- , "testNormalize2 -- preparation")
- doc.normalize()
- self.confirm(len(root.childNodes) == 2
- and root.childNodes.length == 2
- and len(root.childNodes[0].childNodes) == 2
- and root.childNodes[0].childNodes.length == 2
- and len(root.childNodes[1].childNodes) == 2
- and root.childNodes[1].childNodes.length == 2
- and len(root.childNodes[1].childNodes[0].childNodes) == 1
- and root.childNodes[1].childNodes[0].childNodes.length == 1
- , "testNormalize2 -- childNodes lengths")
- self.confirm(root.childNodes[0].childNodes[1].data == "tx"
- and root.childNodes[1].childNodes[0].childNodes[0].data == "t2x2"
- and root.childNodes[1].childNodes[1].data == "t3x3"
- , "testNormalize2 -- joined text fields")
- self.confirm(root.childNodes[0].childNodes[1].nextSibling is None
- and root.childNodes[0].childNodes[1].previousSibling
- is root.childNodes[0].childNodes[0]
- and root.childNodes[0].childNodes[0].previousSibling is None
- and root.childNodes[0].childNodes[0].nextSibling
- is root.childNodes[0].childNodes[1]
- and root.childNodes[1].childNodes[1].nextSibling is None
- and root.childNodes[1].childNodes[1].previousSibling
- is root.childNodes[1].childNodes[0]
- and root.childNodes[1].childNodes[0].previousSibling is None
- and root.childNodes[1].childNodes[0].nextSibling
- is root.childNodes[1].childNodes[1]
- , "testNormalize2 -- sibling pointers")
- doc.unlink()
- def testBug0777884(self):
- doc = parseString("<o>text</o>")
- text = doc.documentElement.childNodes[0]
- self.assertEqual(text.nodeType, Node.TEXT_NODE)
- # Should run quietly, doing nothing.
- text.normalize()
- doc.unlink()
- def testBug1433694(self):
- doc = parseString("<o><i/>t</o>")
- node = doc.documentElement
- node.childNodes[1].nodeValue = ""
- node.normalize()
- self.confirm(node.childNodes[-1].nextSibling is None,
- "Final child's .nextSibling should be None")
- def testSiblings(self):
- doc = parseString("<doc><?pi?>text?<elm/></doc>")
- root = doc.documentElement
- (pi, text, elm) = root.childNodes
- self.confirm(pi.nextSibling is text and
- pi.previousSibling is None and
- text.nextSibling is elm and
- text.previousSibling is pi and
- elm.nextSibling is None and
- elm.previousSibling is text, "testSiblings")
- doc.unlink()
- def testParents(self):
- doc = parseString(
- "<doc><elm1><elm2/><elm2><elm3/></elm2></elm1></doc>")
- root = doc.documentElement
- elm1 = root.childNodes[0]
- (elm2a, elm2b) = elm1.childNodes
- elm3 = elm2b.childNodes[0]
- self.confirm(root.parentNode is doc and
- elm1.parentNode is root and
- elm2a.parentNode is elm1 and
- elm2b.parentNode is elm1 and
- elm3.parentNode is elm2b, "testParents")
- doc.unlink()
- def testNodeListItem(self):
- doc = parseString("<doc><e/><e/></doc>")
- children = doc.childNodes
- docelem = children[0]
- self.confirm(children[0] is children.item(0)
- and children.item(1) is None
- and docelem.childNodes.item(0) is docelem.childNodes[0]
- and docelem.childNodes.item(1) is docelem.childNodes[1]
- and docelem.childNodes.item(0).childNodes.item(0) is None,
- "test NodeList.item()")
- doc.unlink()
- def testEncodings(self):
- doc = parseString('<foo>€</foo>')
- self.assertEqual(doc.toxml(),
- '<?xml version="1.0" ?><foo>\u20ac</foo>')
- self.assertEqual(doc.toxml('utf-8'),
- b'<?xml version="1.0" encoding="utf-8"?><foo>\xe2\x82\xac</foo>')
- self.assertEqual(doc.toxml('iso-8859-15'),
- b'<?xml version="1.0" encoding="iso-8859-15"?><foo>\xa4</foo>')
- self.assertEqual(doc.toxml('us-ascii'),
- b'<?xml version="1.0" encoding="us-ascii"?><foo>€</foo>')
- self.assertEqual(doc.toxml('utf-16'),
- '<?xml version="1.0" encoding="utf-16"?>'
- '<foo>\u20ac</foo>'.encode('utf-16'))
- # Verify that character decoding errors raise exceptions instead
- # of crashing
- if pyexpat.version_info >= (2, 4, 5):
- self.assertRaises(ExpatError, parseString,
- b'<fran\xe7ais></fran\xe7ais>')
- self.assertRaises(ExpatError, parseString,
- b'<franais>Comment \xe7a va ? Tr\xe8s bien ?</franais>')
- else:
- self.assertRaises(UnicodeDecodeError, parseString,
- b'<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
- doc.unlink()
- def testStandalone(self):
- doc = parseString('<foo>€</foo>')
- self.assertEqual(doc.toxml(),
- '<?xml version="1.0" ?><foo>\u20ac</foo>')
- self.assertEqual(doc.toxml(standalone=None),
- '<?xml version="1.0" ?><foo>\u20ac</foo>')
- self.assertEqual(doc.toxml(standalone=True),
- '<?xml version="1.0" standalone="yes"?><foo>\u20ac</foo>')
- self.assertEqual(doc.toxml(standalone=False),
- '<?xml version="1.0" standalone="no"?><foo>\u20ac</foo>')
- self.assertEqual(doc.toxml('utf-8', True),
- b'<?xml version="1.0" encoding="utf-8" standalone="yes"?>'
- b'<foo>\xe2\x82\xac</foo>')
- doc.unlink()
- class UserDataHandler:
- called = 0
- def handle(self, operation, key, data, src, dst):
- dst.setUserData(key, data + 1, self)
- src.setUserData(key, None, None)
- self.called = 1
- def testUserData(self):
- dom = Document()
- n = dom.createElement('e')
- self.confirm(n.getUserData("foo") is None)
- n.setUserData("foo", None, None)
- self.confirm(n.getUserData("foo") is None)
- n.setUserData("foo", 12, 12)
- n.setUserData("bar", 13, 13)
- self.confirm(n.getUserData("foo") == 12)
- self.confirm(n.getUserData("bar") == 13)
- n.setUserData("foo", None, None)
- self.confirm(n.getUserData("foo") is None)
- self.confirm(n.getUserData("bar") == 13)
- handler = self.UserDataHandler()
- n.setUserData("bar", 12, handler)
- c = n.cloneNode(1)
- self.confirm(handler.called
- and n.getUserData("bar") is None
- and c.getUserData("bar") == 13)
- n.unlink()
- c.unlink()
- dom.unlink()
- def checkRenameNodeSharedConstraints(self, doc, node):
- # Make sure illegal NS usage is detected:
- self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node,
- "http://xml.python.org/ns", "xmlns:foo")
- doc2 = parseString("<doc/>")
- self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node,
- xml.dom.EMPTY_NAMESPACE, "foo")
- def testRenameAttribute(self):
- doc = parseString("<doc a='v'/>")
- elem = doc.documentElement
- attrmap = elem.attributes
- attr = elem.attributes['a']
- # Simple renaming
- attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b")
- self.confirm(attr.name == "b"
- and attr.nodeName == "b"
- and attr.localName is None
- and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
- and attr.prefix is None
- and attr.value == "v"
- and elem.getAttributeNode("a") is None
- and elem.getAttributeNode("b").isSameNode(attr)
- and attrmap["b"].isSameNode(attr)
- and attr.ownerDocument.isSameNode(doc)
- and attr.ownerElement.isSameNode(elem))
- # Rename to have a namespace, no prefix
- attr = doc.renameNode(attr, "http://xml.python.org/ns", "c")
- self.confirm(attr.name == "c"
- and attr.nodeName == "c"
- and attr.localName == "c"
- and attr.namespaceURI == "http://xml.python.org/ns"
- and attr.prefix is None
- and attr.value == "v"
- and elem.getAttributeNode("a") is None
- and elem.getAttributeNode("b") is None
- and elem.getAttributeNode("c").isSameNode(attr)
- and elem.getAttributeNodeNS(
- "http://xml.python.org/ns", "c").isSameNode(attr)
- and attrmap["c"].isSameNode(attr)
- and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr))
- # Rename to have a namespace, with prefix
- attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d")
- self.confirm(attr.name == "p:d"
- and attr.nodeName == "p:d"
- and attr.localName == "d"
- and attr.namespaceURI == "http://xml.python.org/ns2"
- and attr.prefix == "p"
- and attr.value == "v"
- and elem.getAttributeNode("a") is None
- and elem.getAttributeNode("b") is None
- and elem.getAttributeNode("c") is None
- and elem.getAttributeNodeNS(
- "http://xml.python.org/ns", "c") is None
- and elem.getAttributeNode("p:d").isSameNode(attr)
- and elem.getAttributeNodeNS(
- "http://xml.python.org/ns2", "d").isSameNode(attr)
- and attrmap["p:d"].isSameNode(attr)
- and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr))
- # Rename back to a simple non-NS node
- attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e")
- self.confirm(attr.name == "e"
- and attr.nodeName == "e"
- and attr.localName is None
- and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE
- and attr.prefix is None
- and attr.value == "v"
- and elem.getAttributeNode("a") is None
- and elem.getAttributeNode("b") is None
- and elem.getAttributeNode("c") is None
- and elem.getAttributeNode("p:d") is None
- and elem.getAttributeNodeNS(
- "http://xml.python.org/ns", "c") is None
- and elem.getAttributeNode("e").isSameNode(attr)
- and attrmap["e"].isSameNode(attr))
- self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr,
- "http://xml.python.org/ns", "xmlns")
- self.checkRenameNodeSharedConstraints(doc, attr)
- doc.unlink()
- def testRenameElement(self):
- doc = parseString("<doc/>")
- elem = doc.documentElement
- # Simple renaming
- elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a")
- self.confirm(elem.tagName == "a"
- and elem.nodeName == "a"
- and elem.localName is None
- and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
- and elem.prefix is None
- and elem.ownerDocument.isSameNode(doc))
- # Rename to have a namespace, no prefix
- elem = doc.renameNode(elem, "http://xml.python.org/ns", "b")
- self.confirm(elem.tagName == "b"
- and elem.nodeName == "b"
- and elem.localName == "b"
- and elem.namespaceURI == "http://xml.python.org/ns"
- and elem.prefix is None
- and elem.ownerDocument.isSameNode(doc))
- # Rename to have a namespace, with prefix
- elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c")
- self.confirm(elem.tagName == "p:c"
- and elem.nodeName == "p:c"
- and elem.localName == "c"
- and elem.namespaceURI == "http://xml.python.org/ns2"
- and elem.prefix == "p"
- and elem.ownerDocument.isSameNode(doc))
- # Rename back to a simple non-NS node
- elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d")
- self.confirm(elem.tagName == "d"
- and elem.nodeName == "d"
- and elem.localName is None
- and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE
- and elem.prefix is None
- and elem.ownerDocument.isSameNode(doc))
- self.checkRenameNodeSharedConstraints(doc, elem)
- doc.unlink()
- def testRenameOther(self):
- # We have to create a comment node explicitly since not all DOM
- # builders used with minidom add comments to the DOM.
- doc = xml.dom.minidom.getDOMImplementation().createDocument(
- xml.dom.EMPTY_NAMESPACE, "e", None)
- node = doc.createComment("comment")
- self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node,
- xml.dom.EMPTY_NAMESPACE, "foo")
- doc.unlink()
- def testWholeText(self):
- doc = parseString("<doc>a</doc>")
- elem = doc.documentElement
- text = elem.childNodes[0]
- self.assertEqual(text.nodeType, Node.TEXT_NODE)
- self.checkWholeText(text, "a")
- elem.appendChild(doc.createTextNode("b"))
- self.checkWholeText(text, "ab")
- elem.insertBefore(doc.createCDATASection("c"), text)
- self.checkWholeText(text, "cab")
- # make sure we don't cross other nodes
- splitter = doc.createComment("comment")
- elem.appendChild(splitter)
- text2 = doc.createTextNode("d")
- elem.appendChild(text2)
- self.checkWholeText(text, "cab")
- self.checkWholeText(text2, "d")
- x = doc.createElement("x")
- elem.replaceChild(x, splitter)
- splitter = x
- self.checkWholeText(text, "cab")
- self.checkWholeText(text2, "d")
- x = doc.createProcessingInstruction("y", "z")
- elem.replaceChild(x, splitter)
- splitter = x
- self.checkWholeText(text, "cab")
- self.checkWholeText(text2, "d")
- elem.removeChild(splitter)
- self.checkWholeText(text, "cabd")
- self.checkWholeText(text2, "cabd")
- def testPatch1094164(self):
- doc = parseString("<doc><e/></doc>")
- elem = doc.documentElement
- e = elem.firstChild
- self.confirm(e.parentNode is elem, "Before replaceChild()")
- # Check that replacing a child with itself leaves the tree unchanged
- elem.replaceChild(e, e)
- self.confirm(e.parentNode is elem, "After replaceChild()")
- def testReplaceWholeText(self):
- def setup():
- doc = parseString("<doc>a<e/>d</doc>")
- elem = doc.documentElement
- text1 = elem.firstChild
- text2 = elem.lastChild
- splitter = text1.nextSibling
- elem.insertBefore(doc.createTextNode("b"), splitter)
- elem.insertBefore(doc.createCDATASection("c"), text1)
- return doc, elem, text1, splitter, text2
- doc, elem, text1, splitter, text2 = setup()
- text = text1.replaceWholeText("new content")
- self.checkWholeText(text, "new content")
- self.checkWholeText(text2, "d")
- self.confirm(len(elem.childNodes) == 3)
- doc, elem, text1, splitter, text2 = setup()
- text = text2.replaceWholeText("new content")
- self.checkWholeText(text, "new content")
- self.checkWholeText(text1, "cab")
- self.confirm(len(elem.childNodes) == 5)
- doc, elem, text1, splitter, text2 = setup()
- text = text1.replaceWholeText("")
- self.checkWholeText(text2, "d")
- self.confirm(text is None
- and len(elem.childNodes) == 2)
- def testSchemaType(self):
- doc = parseString(
- "<!DOCTYPE doc [\n"
- " <!ENTITY e1 SYSTEM 'http://xml.python.org/e1'>\n"
- " <!ENTITY e2 SYSTEM 'http://xml.python.org/e2'>\n"
- " <!ATTLIST doc id ID #IMPLIED \n"
- " ref IDREF #IMPLIED \n"
- " refs IDREFS #IMPLIED \n"
- " enum (a|b) #IMPLIED \n"
- " ent ENTITY #IMPLIED \n"
- " ents ENTITIES #IMPLIED \n"
- " nm NMTOKEN #IMPLIED \n"
- " nms NMTOKENS #IMPLIED \n"
- " text CDATA #IMPLIED \n"
- " >\n"
- "]><doc id='name' notid='name' text='splat!' enum='b'"
- " ref='name' refs='name name' ent='e1' ents='e1 e2'"
- " nm='123' nms='123 abc' />")
- elem = doc.documentElement
- # We don't want to rely on any specific loader at this point, so
- # just make sure we can get to all the names, and that the
- # DTD-based namespace is right. The names can vary by loader
- # since each supports a different level of DTD information.
- t = elem.schemaType
- self.confirm(t.name is None
- and t.namespace == xml.dom.EMPTY_NAMESPACE)
- names = "id notid text enum ref refs ent ents nm nms".split()
- for name in names:
- a = elem.getAttributeNode(name)
- t = a.schemaType
- self.confirm(hasattr(t, "name")
- and t.namespace == xml.dom.EMPTY_NAMESPACE)
- def testSetIdAttribute(self):
- doc = parseString("<doc a1='v' a2='w'/>")
- e = doc.documentElement
- a1 = e.getAttributeNode("a1")
- a2 = e.getAttributeNode("a2")
- self.confirm(doc.getElementById("v") is None
- and not a1.isId
- and not a2.isId)
- e.setIdAttribute("a1")
- self.confirm(e.isSameNode(doc.getElementById("v"))
- and a1.isId
- and not a2.isId)
- e.setIdAttribute("a2")
- self.confirm(e.isSameNode(doc.getElementById("v"))
- and e.isSameNode(doc.getElementById("w"))
- and a1.isId
- and a2.isId)
- # replace the a1 node; the new node should *not* be an ID
- a3 = doc.createAttribute("a1")
- a3.value = "v"
- e.setAttributeNode(a3)
- self.confirm(doc.getElementById("v") is None
- and e.isSameNode(doc.getElementById("w"))
- and not a1.isId
- and a2.isId
- and not a3.isId)
- # renaming an attribute should not affect its ID-ness:
- doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
- self.confirm(e.isSameNode(doc.getElementById("w"))
- and a2.isId)
- def testSetIdAttributeNS(self):
- NS1 = "http://xml.python.org/ns1"
- NS2 = "http://xml.python.org/ns2"
- doc = parseString("<doc"
- " xmlns:ns1='" + NS1 + "'"
- " xmlns:ns2='" + NS2 + "'"
- " ns1:a1='v' ns2:a2='w'/>")
- e = doc.documentElement
- a1 = e.getAttributeNodeNS(NS1, "a1")
- a2 = e.getAttributeNodeNS(NS2, "a2")
- self.confirm(doc.getElementById("v") is None
- and not a1.isId
- and not a2.isId)
- e.setIdAttributeNS(NS1, "a1")
- self.confirm(e.isSameNode(doc.getElementById("v"))
- and a1.isId
- and not a2.isId)
- e.setIdAttributeNS(NS2, "a2")
- self.confirm(e.isSameNode(doc.getElementById("v"))
- and e.isSameNode(doc.getElementById("w"))
- and a1.isId
- and a2.isId)
- # replace the a1 node; the new node should *not* be an ID
- a3 = doc.createAttributeNS(NS1, "a1")
- a3.value = "v"
- e.setAttributeNode(a3)
- self.confirm(e.isSameNode(doc.getElementById("w")))
- self.confirm(not a1.isId)
- self.confirm(a2.isId)
- self.confirm(not a3.isId)
- self.confirm(doc.getElementById("v") is None)
- # renaming an attribute should not affect its ID-ness:
- doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
- self.confirm(e.isSameNode(doc.getElementById("w"))
- and a2.isId)
- def testSetIdAttributeNode(self):
- NS1 = "http://xml.python.org/ns1"
- NS2 = "http://xml.python.org/ns2"
- doc = parseString("<doc"
- " xmlns:ns1='" + NS1 + "'"
- " xmlns:ns2='" + NS2 + "'"
- " ns1:a1='v' ns2:a2='w'/>")
- e = doc.documentElement
- a1 = e.getAttributeNodeNS(NS1, "a1")
- a2 = e.getAttributeNodeNS(NS2, "a2")
- self.confirm(doc.getElementById("v") is None
- and not a1.isId
- and not a2.isId)
- e.setIdAttributeNode(a1)
- self.confirm(e.isSameNode(doc.getElementById("v"))
- and a1.isId
- and not a2.isId)
- e.setIdAttributeNode(a2)
- self.confirm(e.isSameNode(doc.getElementById("v"))
- and e.isSameNode(doc.getElementById("w"))
- and a1.isId
- and a2.isId)
- # replace the a1 node; the new node should *not* be an ID
- a3 = doc.createAttributeNS(NS1, "a1")
- a3.value = "v"
- e.setAttributeNode(a3)
- self.confirm(e.isSameNode(doc.getElementById("w")))
- self.confirm(not a1.isId)
- self.confirm(a2.isId)
- self.confirm(not a3.isId)
- self.confirm(doc.getElementById("v") is None)
- # renaming an attribute should not affect its ID-ness:
- doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an")
- self.confirm(e.isSameNode(doc.getElementById("w"))
- and a2.isId)
- def assert_recursive_equal(self, doc, doc2):
- stack = [(doc, doc2)]
- while stack:
- n1, n2 = stack.pop()
- self.assertEqual(n1.nodeType, n2.nodeType)
- self.assertEqual(len(n1.childNodes), len(n2.childNodes))
- self.assertEqual(n1.nodeName, n2.nodeName)
- self.assertFalse(n1.isSameNode(n2))
- self.assertFalse(n2.isSameNode(n1))
- if n1.nodeType == Node.DOCUMENT_TYPE_NODE:
- len(n1.entities)
- len(n2.entities)
- len(n1.notations)
- len(n2.notations)
- self.assertEqual(len(n1.entities), len(n2.entities))
- self.assertEqual(len(n1.notations), len(n2.notations))
- for i in range(len(n1.notations)):
- # XXX this loop body doesn't seem to be executed?
- no1 = n1.notations.item(i)
- no2 = n1.notations.item(i)
- self.assertEqual(no1.name, no2.name)
- self.assertEqual(no1.publicId, no2.publicId)
- self.assertEqual(no1.systemId, no2.systemId)
- stack.append((no1, no2))
- for i in range(len(n1.entities)):
- e1 = n1.entities.item(i)
- e2 = n2.entities.item(i)
- self.assertEqual(e1.notationName, e2.notationName)
- self.assertEqual(e1.publicId, e2.publicId)
- self.assertEqual(e1.systemId, e2.systemId)
- stack.append((e1, e2))
- if n1.nodeType != Node.DOCUMENT_NODE:
- self.assertTrue(n1.ownerDocument.isSameNode(doc))
- self.assertTrue(n2.ownerDocument.isSameNode(doc2))
- for i in range(len(n1.childNodes)):
- stack.append((n1.childNodes[i], n2.childNodes[i]))
- def testPickledDocument(self):
- doc = parseString(sample)
- for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
- s = pickle.dumps(doc, proto)
- doc2 = pickle.loads(s)
- self.assert_recursive_equal(doc, doc2)
- def testDeepcopiedDocument(self):
- doc = parseString(sample)
- doc2 = copy.deepcopy(doc)
- self.assert_recursive_equal(doc, doc2)
- def testSerializeCommentNodeWithDoubleHyphen(self):
- doc = create_doc_without_doctype()
- doc.appendChild(doc.createComment("foo--bar"))
- self.assertRaises(ValueError, doc.toxml)
- def testEmptyXMLNSValue(self):
- doc = parseString("<element xmlns=''>\n"
- "<foo/>\n</element>")
- doc2 = parseString(doc.toxml())
- self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
- def testExceptionOnSpacesInXMLNSValue(self):
- if pyexpat.version_info >= (2, 4, 5):
- context = self.assertRaisesRegex(ExpatError, 'syntax error')
- else:
- context = self.assertRaisesRegex(ValueError, 'Unsupported syntax')
- with context:
- parseString('<element xmlns:abc="http:abc.com/de f g/hi/j k"><abc:foo /></element>')
- def testDocRemoveChild(self):
- doc = parse(tstfile)
- title_tag = doc.documentElement.getElementsByTagName("TITLE")[0]
- self.assertRaises( xml.dom.NotFoundErr, doc.removeChild, title_tag)
- num_children_before = len(doc.childNodes)
- doc.removeChild(doc.childNodes[0])
- num_children_after = len(doc.childNodes)
- self.assertTrue(num_children_after == num_children_before - 1)
- def testProcessingInstructionNameError(self):
- # wrong variable in .nodeValue property will
- # lead to "NameError: name 'data' is not defined"
- doc = parse(tstfile)
- pi = doc.createProcessingInstruction("y", "z")
- pi.nodeValue = "crash"
- def test_minidom_attribute_order(self):
- xml_str = '<?xml version="1.0" ?><curriculum status="public" company="example"/>'
- doc = parseString(xml_str)
- output = io.StringIO()
- doc.writexml(output)
- self.assertEqual(output.getvalue(), xml_str)
- def test_toxml_with_attributes_ordered(self):
- xml_str = '<?xml version="1.0" ?><curriculum status="public" company="example"/>'
- doc = parseString(xml_str)
- self.assertEqual(doc.toxml(), xml_str)
- def test_toprettyxml_with_attributes_ordered(self):
- xml_str = '<?xml version="1.0" ?><curriculum status="public" company="example"/>'
- doc = parseString(xml_str)
- self.assertEqual(doc.toprettyxml(),
- '<?xml version="1.0" ?>\n'
- '<curriculum status="public" company="example"/>\n')
- def test_toprettyxml_with_cdata(self):
- xml_str = '<?xml version="1.0" ?><root><node><![CDATA[</data>]]></node></root>'
- doc = parseString(xml_str)
- self.assertEqual(doc.toprettyxml(),
- '<?xml version="1.0" ?>\n'
- '<root>\n'
- '\t<node><![CDATA[</data>]]></node>\n'
- '</root>\n')
- def test_cdata_parsing(self):
- xml_str = '<?xml version="1.0" ?><root><node><![CDATA[</data>]]></node></root>'
- dom1 = parseString(xml_str)
- self.checkWholeText(dom1.getElementsByTagName('node')[0].firstChild, '</data>')
- dom2 = parseString(dom1.toprettyxml())
- self.checkWholeText(dom2.getElementsByTagName('node')[0].firstChild, '</data>')
- if __name__ == "__main__":
- unittest.main()
|