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