Package lxml :: Package tests :: Module test_etree
[hide private]
[frames] | no frames]

Source Code for Module lxml.tests.test_etree

   1  # -*- coding: utf-8 -*- 
   2   
   3  """ 
   4  Tests specific to the extended etree API 
   5   
   6  Tests that apply to the general ElementTree API should go into 
   7  test_elementtree 
   8  """ 
   9   
  10  import os.path 
  11  import unittest 
  12  import copy 
  13  import sys 
  14  import re 
  15  import gc 
  16  import operator 
  17  import tempfile 
  18  import zlib 
  19  import gzip 
  20   
  21  this_dir = os.path.dirname(__file__) 
  22  if this_dir not in sys.path: 
  23      sys.path.insert(0, this_dir) # needed for Py3 
  24   
  25  from common_imports import etree, StringIO, BytesIO, HelperTestCase 
  26  from common_imports import fileInTestDir, fileUrlInTestDir, read_file, path2url 
  27  from common_imports import SillyFileLike, LargeFileLikeUnicode, doctest, make_doctest 
  28  from common_imports import canonicalize, sorted, _str, _bytes 
  29   
  30  print("") 
  31  print("TESTED VERSION: %s" % etree.__version__) 
  32  print("    Python:           " + repr(sys.version_info)) 
  33  print("    lxml.etree:       " + repr(etree.LXML_VERSION)) 
  34  print("    libxml used:      " + repr(etree.LIBXML_VERSION)) 
  35  print("    libxml compiled:  " + repr(etree.LIBXML_COMPILED_VERSION)) 
  36  print("    libxslt used:     " + repr(etree.LIBXSLT_VERSION)) 
  37  print("    libxslt compiled: " + repr(etree.LIBXSLT_COMPILED_VERSION)) 
  38  print("") 
  39   
  40  try: 
  41      _unicode = unicode 
  42  except NameError: 
  43      # Python 3 
  44      _unicode = str 
  45   
46 -class ETreeOnlyTestCase(HelperTestCase):
47 """Tests only for etree, not ElementTree""" 48 etree = etree 49
50 - def test_version(self):
51 self.assertTrue(isinstance(etree.__version__, _unicode)) 52 self.assertTrue(isinstance(etree.LXML_VERSION, tuple)) 53 self.assertEqual(len(etree.LXML_VERSION), 4) 54 self.assertTrue(isinstance(etree.LXML_VERSION[0], int)) 55 self.assertTrue(isinstance(etree.LXML_VERSION[1], int)) 56 self.assertTrue(isinstance(etree.LXML_VERSION[2], int)) 57 self.assertTrue(isinstance(etree.LXML_VERSION[3], int)) 58 self.assertTrue(etree.__version__.startswith( 59 str(etree.LXML_VERSION[0])))
60
61 - def test_c_api(self):
62 if hasattr(self.etree, '__pyx_capi__'): 63 # newer Pyrex compatible C-API 64 self.assertTrue(isinstance(self.etree.__pyx_capi__, dict)) 65 self.assertTrue(len(self.etree.__pyx_capi__) > 0) 66 else: 67 # older C-API mechanism 68 self.assertTrue(hasattr(self.etree, '_import_c_api'))
69
70 - def test_element_names(self):
71 Element = self.etree.Element 72 el = Element('name') 73 self.assertEqual(el.tag, 'name') 74 el = Element('{}name') 75 self.assertEqual(el.tag, 'name')
76
77 - def test_element_name_empty(self):
78 Element = self.etree.Element 79 el = Element('name') 80 self.assertRaises(ValueError, Element, '{}') 81 self.assertRaises(ValueError, setattr, el, 'tag', '{}') 82 83 self.assertRaises(ValueError, Element, '{test}') 84 self.assertRaises(ValueError, setattr, el, 'tag', '{test}')
85
86 - def test_element_name_colon(self):
87 Element = self.etree.Element 88 self.assertRaises(ValueError, Element, 'p:name') 89 self.assertRaises(ValueError, Element, '{test}p:name') 90 91 el = Element('name') 92 self.assertRaises(ValueError, setattr, el, 'tag', 'p:name')
93
94 - def test_element_name_quote(self):
95 Element = self.etree.Element 96 self.assertRaises(ValueError, Element, "p'name") 97 self.assertRaises(ValueError, Element, 'p"name') 98 99 self.assertRaises(ValueError, Element, "{test}p'name") 100 self.assertRaises(ValueError, Element, '{test}p"name') 101 102 el = Element('name') 103 self.assertRaises(ValueError, setattr, el, 'tag', "p'name") 104 self.assertRaises(ValueError, setattr, el, 'tag', 'p"name')
105
106 - def test_element_name_space(self):
107 Element = self.etree.Element 108 self.assertRaises(ValueError, Element, ' name ') 109 self.assertRaises(ValueError, Element, 'na me') 110 self.assertRaises(ValueError, Element, '{test} name') 111 112 el = Element('name') 113 self.assertRaises(ValueError, setattr, el, 'tag', ' name ')
114
115 - def test_subelement_name_empty(self):
116 Element = self.etree.Element 117 SubElement = self.etree.SubElement 118 119 el = Element('name') 120 self.assertRaises(ValueError, SubElement, el, '{}') 121 self.assertRaises(ValueError, SubElement, el, '{test}')
122
123 - def test_subelement_name_colon(self):
124 Element = self.etree.Element 125 SubElement = self.etree.SubElement 126 127 el = Element('name') 128 self.assertRaises(ValueError, SubElement, el, 'p:name') 129 self.assertRaises(ValueError, SubElement, el, '{test}p:name')
130
131 - def test_subelement_name_quote(self):
132 Element = self.etree.Element 133 SubElement = self.etree.SubElement 134 135 el = Element('name') 136 self.assertRaises(ValueError, SubElement, el, "p'name") 137 self.assertRaises(ValueError, SubElement, el, "{test}p'name") 138 139 self.assertRaises(ValueError, SubElement, el, 'p"name') 140 self.assertRaises(ValueError, SubElement, el, '{test}p"name')
141
142 - def test_subelement_name_space(self):
143 Element = self.etree.Element 144 SubElement = self.etree.SubElement 145 146 el = Element('name') 147 self.assertRaises(ValueError, SubElement, el, ' name ') 148 self.assertRaises(ValueError, SubElement, el, 'na me') 149 self.assertRaises(ValueError, SubElement, el, '{test} name')
150
152 Element = self.etree.Element 153 SubElement = self.etree.SubElement 154 155 el = Element('name') 156 self.assertRaises(ValueError, SubElement, el, 'name', {'a b c' : 'abc'}) 157 self.assertRaises(ValueError, SubElement, el, 'name', {'a' : 'a\0\n'}) 158 self.assertEqual(0, len(el))
159
160 - def test_qname_empty(self):
161 QName = self.etree.QName 162 self.assertRaises(ValueError, QName, '') 163 self.assertRaises(ValueError, QName, 'test', '')
164
165 - def test_qname_colon(self):
166 QName = self.etree.QName 167 self.assertRaises(ValueError, QName, 'p:name') 168 self.assertRaises(ValueError, QName, 'test', 'p:name')
169
170 - def test_qname_space(self):
171 QName = self.etree.QName 172 self.assertRaises(ValueError, QName, ' name ') 173 self.assertRaises(ValueError, QName, 'na me') 174 self.assertRaises(ValueError, QName, 'test', ' name')
175
177 # ET doesn't have namespace/localname properties on QNames 178 QName = self.etree.QName 179 namespace, localname = 'http://myns', 'a' 180 qname = QName(namespace, localname) 181 self.assertEqual(namespace, qname.namespace) 182 self.assertEqual(localname, qname.localname)
183
184 - def test_qname_element(self):
185 # ET doesn't have namespace/localname properties on QNames 186 QName = self.etree.QName 187 qname1 = QName('http://myns', 'a') 188 a = self.etree.Element(qname1, nsmap={'p' : 'http://myns'}) 189 190 qname2 = QName(a) 191 self.assertEqual(a.tag, qname1.text) 192 self.assertEqual(qname1.text, qname2.text) 193 self.assertEqual(qname1, qname2)
194
195 - def test_qname_text_resolve(self):
196 # ET doesn't resove QNames as text values 197 etree = self.etree 198 qname = etree.QName('http://myns', 'a') 199 a = etree.Element(qname, nsmap={'p' : 'http://myns'}) 200 a.text = qname 201 202 self.assertEqual("p:a", a.text)
203
204 - def test_nsmap_prefix_invalid(self):
205 etree = self.etree 206 self.assertRaises(ValueError, 207 etree.Element, "root", nsmap={'"' : 'testns'}) 208 self.assertRaises(ValueError, 209 etree.Element, "root", nsmap={'&' : 'testns'}) 210 self.assertRaises(ValueError, 211 etree.Element, "root", nsmap={'a:b' : 'testns'})
212
213 - def test_attribute_has_key(self):
214 # ET in Py 3.x has no "attrib.has_key()" method 215 XML = self.etree.XML 216 217 root = XML(_bytes('<foo bar="Bar" xmlns:ns="http://ns.codespeak.net/test" ns:baz="Baz" />')) 218 self.assertEqual( 219 True, root.attrib.has_key('bar')) 220 self.assertEqual( 221 False, root.attrib.has_key('baz')) 222 self.assertEqual( 223 False, root.attrib.has_key('hah')) 224 self.assertEqual( 225 True, 226 root.attrib.has_key('{http://ns.codespeak.net/test}baz'))
227
228 - def test_attribute_set(self):
229 Element = self.etree.Element 230 root = Element("root") 231 root.set("attr", "TEST") 232 self.assertEqual("TEST", root.get("attr"))
233
234 - def test_attrib_and_keywords(self):
235 Element = self.etree.Element 236 237 root = Element("root") 238 root.set("attr", "TEST") 239 self.assertEqual("TEST", root.attrib["attr"]) 240 241 root2 = Element("root2", root.attrib, attr2='TOAST') 242 self.assertEqual("TEST", root2.attrib["attr"]) 243 self.assertEqual("TOAST", root2.attrib["attr2"]) 244 self.assertEqual(None, root.attrib.get("attr2"))
245
246 - def test_attrib_order(self):
247 Element = self.etree.Element 248 249 keys = ["attr%d" % i for i in range(10)] 250 values = ["TEST-%d" % i for i in range(10)] 251 items = list(zip(keys, values)) 252 253 root = Element("root") 254 for key, value in items: 255 root.set(key, value) 256 self.assertEqual(keys, root.attrib.keys()) 257 self.assertEqual(values, root.attrib.values()) 258 259 root2 = Element("root2", root.attrib, 260 attr_99='TOAST-1', attr_98='TOAST-2') 261 self.assertEqual(['attr_98', 'attr_99'] + keys, 262 root2.attrib.keys()) 263 self.assertEqual(['TOAST-2', 'TOAST-1'] + values, 264 root2.attrib.values()) 265 266 self.assertEqual(keys, root.attrib.keys()) 267 self.assertEqual(values, root.attrib.values())
268
269 - def test_attribute_set_invalid(self):
270 # ElementTree accepts arbitrary attribute values 271 # lxml.etree allows only strings 272 Element = self.etree.Element 273 root = Element("root") 274 self.assertRaises(TypeError, root.set, "newattr", 5) 275 self.assertRaises(TypeError, root.set, "newattr", None)
276
277 - def test_strip_attributes(self):
278 XML = self.etree.XML 279 xml = _bytes('<test a="5" b="10" c="20"><x a="4" b="2"/></test>') 280 281 root = XML(xml) 282 self.etree.strip_attributes(root, 'a') 283 self.assertEqual(_bytes('<test b="10" c="20"><x b="2"></x></test>'), 284 self._writeElement(root)) 285 286 root = XML(xml) 287 self.etree.strip_attributes(root, 'b', 'c') 288 self.assertEqual(_bytes('<test a="5"><x a="4"></x></test>'), 289 self._writeElement(root))
290
291 - def test_strip_attributes_ns(self):
292 XML = self.etree.XML 293 xml = _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20" n:a="5"><x a="4" n:b="2"/></test>') 294 295 root = XML(xml) 296 self.etree.strip_attributes(root, 'a') 297 self.assertEqual( 298 _bytes('<test xmlns:n="http://test/ns" b="10" c="20" n:a="5"><x n:b="2"></x></test>'), 299 self._writeElement(root)) 300 301 root = XML(xml) 302 self.etree.strip_attributes(root, '{http://test/ns}a', 'c') 303 self.assertEqual( 304 _bytes('<test xmlns:n="http://test/ns" a="6" b="10"><x a="4" n:b="2"></x></test>'), 305 self._writeElement(root)) 306 307 root = XML(xml) 308 self.etree.strip_attributes(root, '{http://test/ns}*') 309 self.assertEqual( 310 _bytes('<test xmlns:n="http://test/ns" a="6" b="10" c="20"><x a="4"></x></test>'), 311 self._writeElement(root))
312
313 - def test_strip_elements(self):
314 XML = self.etree.XML 315 xml = _bytes('<test><a><b><c/></b></a><x><a><b/><c/></a></x></test>') 316 317 root = XML(xml) 318 self.etree.strip_elements(root, 'a') 319 self.assertEqual(_bytes('<test><x></x></test>'), 320 self._writeElement(root)) 321 322 root = XML(xml) 323 self.etree.strip_elements(root, 'b', 'c', 'X', 'Y', 'Z') 324 self.assertEqual(_bytes('<test><a></a><x><a></a></x></test>'), 325 self._writeElement(root)) 326 327 root = XML(xml) 328 self.etree.strip_elements(root, 'c') 329 self.assertEqual(_bytes('<test><a><b></b></a><x><a><b></b></a></x></test>'), 330 self._writeElement(root))
331
332 - def test_strip_elements_ns(self):
333 XML = self.etree.XML 334 xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>C</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>') 335 336 root = XML(xml) 337 self.etree.strip_elements(root, 'a') 338 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X</x>XT</test>'), 339 self._writeElement(root)) 340 341 root = XML(xml) 342 self.etree.strip_elements(root, '{urn:a}b', 'c') 343 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>C</b>BT</n:a>AT<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 344 self._writeElement(root)) 345 346 root = XML(xml) 347 self.etree.strip_elements(root, '{urn:a}*', 'c') 348 self.assertEqual(_bytes('<test>TEST<x>X<a>A<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 349 self._writeElement(root)) 350 351 root = XML(xml) 352 self.etree.strip_elements(root, '{urn:a}*', 'c', with_tail=False) 353 self.assertEqual(_bytes('<test>TESTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 354 self._writeElement(root))
355
356 - def test_strip_tags(self):
357 XML = self.etree.XML 358 xml = _bytes('<test>TEST<a>A<b>B<c/>CT</b>BT</a>AT<x>X<a>A<b/>BT<c/>CT</a>AT</x>XT</test>') 359 360 root = XML(xml) 361 self.etree.strip_tags(root, 'a') 362 self.assertEqual(_bytes('<test>TESTA<b>B<c></c>CT</b>BTAT<x>XA<b></b>BT<c></c>CTAT</x>XT</test>'), 363 self._writeElement(root)) 364 365 root = XML(xml) 366 self.etree.strip_tags(root, 'b', 'c', 'X', 'Y', 'Z') 367 self.assertEqual(_bytes('<test>TEST<a>ABCTBT</a>AT<x>X<a>ABTCT</a>AT</x>XT</test>'), 368 self._writeElement(root)) 369 370 root = XML(xml) 371 self.etree.strip_tags(root, 'c') 372 self.assertEqual(_bytes('<test>TEST<a>A<b>BCT</b>BT</a>AT<x>X<a>A<b></b>BTCT</a>AT</x>XT</test>'), 373 self._writeElement(root))
374
375 - def test_strip_tags_pi_comment(self):
376 XML = self.etree.XML 377 PI = self.etree.ProcessingInstruction 378 Comment = self.etree.Comment 379 xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>') 380 381 root = XML(xml) 382 self.etree.strip_tags(root, PI) 383 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->\n<?PI1?>'), 384 self._writeElement(root)) 385 386 root = XML(xml) 387 self.etree.strip_tags(root, Comment) 388 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT<?PI2?></test>\n<!--comment3-->\n<?PI1?>'), 389 self._writeElement(root)) 390 391 root = XML(xml) 392 self.etree.strip_tags(root, PI, Comment) 393 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'), 394 self._writeElement(root)) 395 396 root = XML(xml) 397 self.etree.strip_tags(root, Comment, PI) 398 self.assertEqual(_bytes('<!--comment1-->\n<?PI1?>\n<test>TESTXT</test>\n<!--comment3-->\n<?PI1?>'), 399 self._writeElement(root))
400
402 XML = self.etree.XML 403 ElementTree = self.etree.ElementTree 404 PI = self.etree.ProcessingInstruction 405 Comment = self.etree.Comment 406 xml = _bytes('<!--comment1-->\n<?PI1?>\n<test>TEST<!--comment2-->XT<?PI2?></test>\n<!--comment3-->\n<?PI1?>') 407 408 root = XML(xml) 409 self.etree.strip_tags(ElementTree(root), PI) 410 self.assertEqual(_bytes('<!--comment1-->\n<test>TEST<!--comment2-->XT</test>\n<!--comment3-->'), 411 self._writeElement(root)) 412 413 root = XML(xml) 414 self.etree.strip_tags(ElementTree(root), Comment) 415 self.assertEqual(_bytes('<?PI1?>\n<test>TESTXT<?PI2?></test>\n<?PI1?>'), 416 self._writeElement(root)) 417 418 root = XML(xml) 419 self.etree.strip_tags(ElementTree(root), PI, Comment) 420 self.assertEqual(_bytes('<test>TESTXT</test>'), 421 self._writeElement(root)) 422 423 root = XML(xml) 424 self.etree.strip_tags(ElementTree(root), Comment, PI) 425 self.assertEqual(_bytes('<test>TESTXT</test>'), 426 self._writeElement(root))
427
428 - def test_strip_tags_doc_style(self):
429 XML = self.etree.XML 430 xml = _bytes(''' 431 <div> 432 <div> 433 I like <strong>sheep</strong>. 434 <br/> 435 I like lots of <strong>sheep</strong>. 436 <br/> 437 Click <a href="http://www.sheep.com">here</a> 438 for <a href="http://www.sheep.com">those</a> sheep. 439 <br/> 440 </div> 441 </div> 442 '''.strip()) 443 444 root = XML(xml) 445 self.etree.strip_tags(root, 'a') 446 self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''), xml).replace(_bytes('<br/>'), _bytes('<br></br>')), 447 self._writeElement(root)) 448 449 root = XML(xml) 450 self.etree.strip_tags(root, 'a', 'br') 451 self.assertEqual(re.sub(_bytes('</?a[^>]*>'), _bytes(''), 452 re.sub(_bytes('<br[^>]*>'), _bytes(''), xml)), 453 self._writeElement(root))
454
455 - def test_strip_tags_ns(self):
456 XML = self.etree.XML 457 xml = _bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"/>CT</b>BT</n:a>AT<x>X<a>A<b xmlns="urn:a"/>BT<c xmlns="urn:x"/>CT</a>AT</x>XT</test>') 458 459 root = XML(xml) 460 self.etree.strip_tags(root, 'a') 461 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>XA<b xmlns="urn:a"></b>BT<c xmlns="urn:x"></c>CTAT</x>XT</test>'), 462 self._writeElement(root)) 463 464 root = XML(xml) 465 self.etree.strip_tags(root, '{urn:a}b', 'c') 466 self.assertEqual(_bytes('<test>TEST<n:a xmlns:n="urn:a">A<b>B<c xmlns="urn:c"></c>CT</b>BT</n:a>AT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 467 self._writeElement(root)) 468 469 root = XML(xml) 470 self.etree.strip_tags(root, '{urn:a}*', 'c') 471 self.assertEqual(_bytes('<test>TESTA<b>B<c xmlns="urn:c"></c>CT</b>BTAT<x>X<a>ABT<c xmlns="urn:x"></c>CT</a>AT</x>XT</test>'), 472 self._writeElement(root))
473
474 - def test_strip_tags_and_remove(self):
475 # previously crashed 476 HTML = self.etree.HTML 477 root = HTML(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'))[0][0] 478 self.assertEqual(_bytes('<div><h1>title</h1> <b>foo</b> <p>boo</p></div>'), 479 self.etree.tostring(root)) 480 self.etree.strip_tags(root, 'b') 481 self.assertEqual(_bytes('<div><h1>title</h1> foo <p>boo</p></div>'), 482 self.etree.tostring(root)) 483 root.remove(root[0]) 484 self.assertEqual(_bytes('<div><p>boo</p></div>'), 485 self.etree.tostring(root))
486
487 - def test_pi(self):
488 # lxml.etree separates target and text 489 Element = self.etree.Element 490 SubElement = self.etree.SubElement 491 ProcessingInstruction = self.etree.ProcessingInstruction 492 493 a = Element('a') 494 a.append(ProcessingInstruction('foo', 'some more text')) 495 self.assertEqual(a[0].target, 'foo') 496 self.assertEqual(a[0].text, 'some more text')
497
498 - def test_pi_parse(self):
499 XML = self.etree.XML 500 root = XML(_bytes("<test><?mypi my test ?></test>")) 501 self.assertEqual(root[0].target, "mypi") 502 self.assertEqual(root[0].text, "my test ")
503
505 XML = self.etree.XML 506 root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>")) 507 self.assertEqual(root[0].target, "mypi") 508 self.assertEqual(root[0].get('my'), "1") 509 self.assertEqual(root[0].get('test'), " abc ") 510 self.assertEqual(root[0].get('quotes'), "' '") 511 self.assertEqual(root[0].get('only'), None) 512 self.assertEqual(root[0].get('names'), None) 513 self.assertEqual(root[0].get('nope'), None)
514
516 XML = self.etree.XML 517 root = XML(_bytes("<test><?mypi my='1' test=\" abc \" quotes=\"' '\" only names ?></test>")) 518 self.assertEqual(root[0].target, "mypi") 519 self.assertEqual(root[0].attrib['my'], "1") 520 self.assertEqual(root[0].attrib['test'], " abc ") 521 self.assertEqual(root[0].attrib['quotes'], "' '") 522 self.assertRaises(KeyError, root[0].attrib.__getitem__, 'only') 523 self.assertRaises(KeyError, root[0].attrib.__getitem__, 'names') 524 self.assertRaises(KeyError, root[0].attrib.__getitem__, 'nope')
525
526 - def test_deepcopy_pi(self):
527 # previously caused a crash 528 ProcessingInstruction = self.etree.ProcessingInstruction 529 530 a = ProcessingInstruction("PI", "ONE") 531 b = copy.deepcopy(a) 532 b.text = "ANOTHER" 533 534 self.assertEqual('ONE', a.text) 535 self.assertEqual('ANOTHER', b.text)
536
538 XML = self.etree.XML 539 tostring = self.etree.tostring 540 root = XML(_bytes("<?mypi my test ?><test/><!--comment -->")) 541 tree1 = self.etree.ElementTree(root) 542 self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"), 543 tostring(tree1)) 544 545 tree2 = copy.deepcopy(tree1) 546 self.assertEqual(_bytes("<?mypi my test ?><test/><!--comment -->"), 547 tostring(tree2)) 548 549 root2 = copy.deepcopy(tree1.getroot()) 550 self.assertEqual(_bytes("<test/>"), 551 tostring(root2))
552
554 XML = self.etree.XML 555 tostring = self.etree.tostring 556 xml = _bytes('<!DOCTYPE test [\n<!ENTITY entity "tasty">\n]>\n<test/>') 557 root = XML(xml) 558 tree1 = self.etree.ElementTree(root) 559 self.assertEqual(xml, tostring(tree1)) 560 561 tree2 = copy.deepcopy(tree1) 562 self.assertEqual(xml, tostring(tree2)) 563 564 root2 = copy.deepcopy(tree1.getroot()) 565 self.assertEqual(_bytes("<test/>"), 566 tostring(root2))
567
568 - def test_attribute_set(self):
569 # ElementTree accepts arbitrary attribute values 570 # lxml.etree allows only strings 571 Element = self.etree.Element 572 573 root = Element("root") 574 root.set("attr", "TEST") 575 self.assertEqual("TEST", root.get("attr")) 576 self.assertRaises(TypeError, root.set, "newattr", 5)
577
578 - def test_parse_remove_comments(self):
579 fromstring = self.etree.fromstring 580 tostring = self.etree.tostring 581 XMLParser = self.etree.XMLParser 582 583 xml = _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 584 parser = XMLParser(remove_comments=True) 585 root = fromstring(xml, parser) 586 self.assertEqual( 587 _bytes('<a><b><c/></b></a>'), 588 tostring(root))
589
590 - def test_parse_remove_pis(self):
591 parse = self.etree.parse 592 tostring = self.etree.tostring 593 XMLParser = self.etree.XMLParser 594 595 xml = _bytes('<?test?><a><?A?><b><?B?><c/></b><?C?></a><?tail?>') 596 597 f = BytesIO(xml) 598 tree = parse(f) 599 self.assertEqual( 600 xml, 601 tostring(tree)) 602 603 parser = XMLParser(remove_pis=True) 604 tree = parse(f, parser) 605 self.assertEqual( 606 _bytes('<a><b><c/></b></a>'), 607 tostring(tree))
608
610 # ET raises IOError only 611 parse = self.etree.parse 612 self.assertRaises(TypeError, parse, 'notthere.xml', object())
613
615 # ET removes comments 616 iterparse = self.etree.iterparse 617 tostring = self.etree.tostring 618 619 f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 620 events = list(iterparse(f)) 621 root = events[-1][1] 622 self.assertEqual(3, len(events)) 623 self.assertEqual( 624 _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'), 625 tostring(root))
626
627 - def test_iterparse_comments(self):
628 # ET removes comments 629 iterparse = self.etree.iterparse 630 tostring = self.etree.tostring 631 632 def name(event, el): 633 if event == 'comment': 634 return el.text 635 else: 636 return el.tag
637 638 f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 639 events = list(iterparse(f, events=('end', 'comment'))) 640 root = events[-1][1] 641 self.assertEqual(6, len(events)) 642 self.assertEqual(['A', ' B ', 'c', 'b', 'C', 'a'], 643 [ name(*item) for item in events ]) 644 self.assertEqual( 645 _bytes('<a><!--A--><b><!-- B --><c/></b><!--C--></a>'), 646 tostring(root))
647
648 - def test_iterparse_pis(self):
649 # ET removes pis 650 iterparse = self.etree.iterparse 651 tostring = self.etree.tostring 652 ElementTree = self.etree.ElementTree 653 654 def name(event, el): 655 if event == 'pi': 656 return (el.target, el.text) 657 else: 658 return el.tag
659 660 f = BytesIO('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>') 661 events = list(iterparse(f, events=('end', 'pi'))) 662 root = events[-2][1] 663 self.assertEqual(8, len(events)) 664 self.assertEqual([('pia','a'), ('pib','b'), ('pic','c'), 'c', 'b', 665 ('pid','d'), 'a', ('pie','e')], 666 [ name(*item) for item in events ]) 667 self.assertEqual( 668 _bytes('<?pia a?><a><?pib b?><b><?pic c?><c/></b><?pid d?></a><?pie e?>'), 669 tostring(ElementTree(root))) 670
671 - def test_iterparse_remove_comments(self):
672 iterparse = self.etree.iterparse 673 tostring = self.etree.tostring 674 675 f = BytesIO('<a><!--A--><b><!-- B --><c/></b><!--C--></a>') 676 events = list(iterparse(f, remove_comments=True, 677 events=('end', 'comment'))) 678 root = events[-1][1] 679 self.assertEqual(3, len(events)) 680 self.assertEqual(['c', 'b', 'a'], 681 [ el.tag for (event, el) in events ]) 682 self.assertEqual( 683 _bytes('<a><b><c/></b></a>'), 684 tostring(root))
685
686 - def test_iterparse_broken(self):
687 iterparse = self.etree.iterparse 688 f = BytesIO('<a><b><c/></a>') 689 # ET raises ExpatError, lxml raises XMLSyntaxError 690 self.assertRaises(self.etree.XMLSyntaxError, list, iterparse(f))
691
692 - def test_iterparse_broken_recover(self):
693 iterparse = self.etree.iterparse 694 f = BytesIO('<a><b><c/></a>') 695 it = iterparse(f, events=('start', 'end'), recover=True) 696 events = [(ev, el.tag) for ev, el in it] 697 root = it.root 698 self.assertTrue(root is not None) 699 700 self.assertEqual(1, events.count(('start', 'a'))) 701 self.assertEqual(1, events.count(('end', 'a'))) 702 703 self.assertEqual(1, events.count(('start', 'b'))) 704 self.assertEqual(1, events.count(('end', 'b'))) 705 706 self.assertEqual(1, events.count(('start', 'c'))) 707 self.assertEqual(1, events.count(('end', 'c')))
708
709 - def test_iterparse_broken_multi_recover(self):
710 iterparse = self.etree.iterparse 711 f = BytesIO('<a><b><c/></d><b><c/></a></b>') 712 it = iterparse(f, events=('start', 'end'), recover=True) 713 events = [(ev, el.tag) for ev, el in it] 714 root = it.root 715 self.assertTrue(root is not None) 716 717 self.assertEqual(1, events.count(('start', 'a'))) 718 self.assertEqual(1, events.count(('end', 'a'))) 719 720 self.assertEqual(2, events.count(('start', 'b'))) 721 self.assertEqual(2, events.count(('end', 'b'))) 722 723 self.assertEqual(2, events.count(('start', 'c'))) 724 self.assertEqual(2, events.count(('end', 'c')))
725
726 - def test_iterparse_strip(self):
727 iterparse = self.etree.iterparse 728 f = BytesIO(""" 729 <a> \n \n <b> b test </b> \n 730 731 \n\t <c> \n </c> </a> \n """) 732 iterator = iterparse(f, remove_blank_text=True) 733 text = [ (element.text, element.tail) 734 for event, element in iterator ] 735 self.assertEqual( 736 [(" b test ", None), (" \n ", None), (None, None)], 737 text)
738
739 - def test_iterparse_tag(self):
740 iterparse = self.etree.iterparse 741 f = BytesIO('<a><b><d/></b><c/></a>') 742 743 iterator = iterparse(f, tag="b", events=('start', 'end')) 744 events = list(iterator) 745 root = iterator.root 746 self.assertEqual( 747 [('start', root[0]), ('end', root[0])], 748 events)
749
750 - def test_iterparse_tag_all(self):
751 iterparse = self.etree.iterparse 752 f = BytesIO('<a><b><d/></b><c/></a>') 753 754 iterator = iterparse(f, tag="*", events=('start', 'end')) 755 events = list(iterator) 756 self.assertEqual( 757 8, 758 len(events))
759
760 - def test_iterparse_tag_ns(self):
761 iterparse = self.etree.iterparse 762 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 763 764 iterator = iterparse(f, tag="{urn:test:1}b", events=('start', 'end')) 765 events = list(iterator) 766 root = iterator.root 767 self.assertEqual( 768 [('start', root[0]), ('end', root[0])], 769 events)
770
771 - def test_iterparse_tag_ns_empty(self):
772 iterparse = self.etree.iterparse 773 f = BytesIO('<a><b><d/></b><c/></a>') 774 iterator = iterparse(f, tag="{}b", events=('start', 'end')) 775 events = list(iterator) 776 root = iterator.root 777 self.assertEqual( 778 [('start', root[0]), ('end', root[0])], 779 events) 780 781 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 782 iterator = iterparse(f, tag="{}b", events=('start', 'end')) 783 events = list(iterator) 784 root = iterator.root 785 self.assertEqual([], events)
786
787 - def test_iterparse_tag_ns_all(self):
788 iterparse = self.etree.iterparse 789 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 790 iterator = iterparse(f, tag="{urn:test:1}*", events=('start', 'end')) 791 events = list(iterator) 792 self.assertEqual(8, len(events))
793
794 - def test_iterparse_tag_ns_empty_all(self):
795 iterparse = self.etree.iterparse 796 f = BytesIO('<a xmlns="urn:test:1"><b><d/></b><c/></a>') 797 iterator = iterparse(f, tag="{}*", events=('start', 'end')) 798 events = list(iterator) 799 self.assertEqual([], events) 800 801 f = BytesIO('<a><b><d/></b><c/></a>') 802 iterator = iterparse(f, tag="{}*", events=('start', 'end')) 803 events = list(iterator) 804 self.assertEqual(8, len(events))
805
806 - def test_iterparse_encoding_error(self):
807 text = _str('Søk på nettet') 808 wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>" 809 xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text) 810 ).encode('iso-8859-1') 811 812 self.assertRaises(self.etree.ParseError, 813 list, self.etree.iterparse(BytesIO(xml_latin1)))
814
815 - def test_iterparse_encoding_8bit_override(self):
816 text = _str('Søk på nettet', encoding="UTF-8") 817 wrong_declaration = "<?xml version='1.0' encoding='UTF-8'?>" 818 xml_latin1 = (_str('%s<a>%s</a>') % (wrong_declaration, text) 819 ).encode('iso-8859-1') 820 821 iterator = self.etree.iterparse(BytesIO(xml_latin1), 822 encoding="iso-8859-1") 823 self.assertEqual(1, len(list(iterator))) 824 825 a = iterator.root 826 self.assertEqual(a.text, text)
827
828 - def test_iterparse_keep_cdata(self):
829 tostring = self.etree.tostring 830 f = BytesIO('<root><![CDATA[test]]></root>') 831 context = self.etree.iterparse(f, strip_cdata=False) 832 content = [ el.text for event,el in context ] 833 834 self.assertEqual(['test'], content) 835 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 836 tostring(context.root))
837
838 - def test_parser_encoding_unknown(self):
839 self.assertRaises( 840 LookupError, self.etree.XMLParser, encoding="hopefully unknown")
841
842 - def test_parser_encoding(self):
843 self.etree.XMLParser(encoding="ascii") 844 self.etree.XMLParser(encoding="utf-8") 845 self.etree.XMLParser(encoding="iso-8859-1")
846
847 - def test_feed_parser_recover(self):
848 parser = self.etree.XMLParser(recover=True) 849 850 parser.feed('<?xml version=') 851 parser.feed('"1.0"?><ro') 852 parser.feed('ot><') 853 parser.feed('a test="works"') 854 parser.feed('><othertag/></root') # <a> not closed! 855 parser.feed('>') 856 857 root = parser.close() 858 859 self.assertEqual(root.tag, "root") 860 self.assertEqual(len(root), 1) 861 self.assertEqual(root[0].tag, "a") 862 self.assertEqual(root[0].get("test"), "works") 863 self.assertEqual(len(root[0]), 1) 864 self.assertEqual(root[0][0].tag, "othertag")
865 # FIXME: would be nice to get some errors logged ... 866 #self.assertTrue(len(parser.error_log) > 0, "error log is empty") 867
868 - def test_elementtree_parser_target_type_error(self):
869 assertEqual = self.assertEqual 870 assertFalse = self.assertFalse 871 872 events = [] 873 class Target(object): 874 def start(self, tag, attrib): 875 events.append("start") 876 assertFalse(attrib) 877 assertEqual("TAG", tag)
878 def end(self, tag): 879 events.append("end") 880 assertEqual("TAG", tag) 881 def close(self): 882 return "DONE" # no Element! 883 884 parser = self.etree.XMLParser(target=Target()) 885 tree = self.etree.ElementTree() 886 887 self.assertRaises(TypeError, 888 tree.parse, BytesIO("<TAG/>"), parser=parser) 889 self.assertEqual(["start", "end"], events) 890
891 - def test_parser_target_feed_exception(self):
892 # ET doesn't call .close() on errors 893 events = [] 894 class Target(object): 895 def start(self, tag, attrib): 896 events.append("start-" + tag)
897 def end(self, tag): 898 events.append("end-" + tag) 899 if tag == 'a': 900 raise ValueError("dead and gone") 901 def data(self, data): 902 events.append("data-" + data) 903 def close(self): 904 events.append("close") 905 return "DONE" 906 907 parser = self.etree.XMLParser(target=Target()) 908 909 try: 910 parser.feed(_bytes('<root>A<a>ca</a>B</root>')) 911 done = parser.close() 912 self.fail("error expected, but parsing succeeded") 913 except ValueError: 914 done = 'value error received as expected' 915 916 self.assertEqual(["start-root", "data-A", "start-a", 917 "data-ca", "end-a", "close"], 918 events) 919
920 - def test_parser_target_fromstring_exception(self):
921 # ET doesn't call .close() on errors 922 events = [] 923 class Target(object): 924 def start(self, tag, attrib): 925 events.append("start-" + tag)
926 def end(self, tag): 927 events.append("end-" + tag) 928 if tag == 'a': 929 raise ValueError("dead and gone") 930 def data(self, data): 931 events.append("data-" + data) 932 def close(self): 933 events.append("close") 934 return "DONE" 935 936 parser = self.etree.XMLParser(target=Target()) 937 938 try: 939 done = self.etree.fromstring(_bytes('<root>A<a>ca</a>B</root>'), 940 parser=parser) 941 self.fail("error expected, but parsing succeeded") 942 except ValueError: 943 done = 'value error received as expected' 944 945 self.assertEqual(["start-root", "data-A", "start-a", 946 "data-ca", "end-a", "close"], 947 events) 948
949 - def test_parser_target_comment(self):
950 events = [] 951 class Target(object): 952 def start(self, tag, attrib): 953 events.append("start-" + tag)
954 def end(self, tag): 955 events.append("end-" + tag) 956 def data(self, data): 957 events.append("data-" + data) 958 def comment(self, text): 959 events.append("comment-" + text) 960 def close(self): 961 return "DONE" 962 963 parser = self.etree.XMLParser(target=Target()) 964 965 parser.feed(_bytes('<!--a--><root>A<!--b--><sub/><!--c-->B</root><!--d-->')) 966 done = parser.close() 967 968 self.assertEqual("DONE", done) 969 self.assertEqual(["comment-a", "start-root", "data-A", "comment-b", 970 "start-sub", "end-sub", "comment-c", "data-B", 971 "end-root", "comment-d"], 972 events) 973
974 - def test_parser_target_pi(self):
975 events = [] 976 class Target(object): 977 def start(self, tag, attrib): 978 events.append("start-" + tag)
979 def end(self, tag): 980 events.append("end-" + tag) 981 def data(self, data): 982 events.append("data-" + data) 983 def pi(self, target, data): 984 events.append("pi-" + target + "-" + data) 985 def close(self): 986 return "DONE" 987 988 parser = self.etree.XMLParser(target=Target()) 989 990 parser.feed(_bytes('<?test a?><root>A<?test b?>B</root><?test c?>')) 991 done = parser.close() 992 993 self.assertEqual("DONE", done) 994 self.assertEqual(["pi-test-a", "start-root", "data-A", "pi-test-b", 995 "data-B", "end-root", "pi-test-c"], 996 events) 997
998 - def test_parser_target_cdata(self):
999 events = [] 1000 class Target(object): 1001 def start(self, tag, attrib): 1002 events.append("start-" + tag)
1003 def end(self, tag): 1004 events.append("end-" + tag) 1005 def data(self, data): 1006 events.append("data-" + data) 1007 def close(self): 1008 return "DONE" 1009 1010 parser = self.etree.XMLParser(target=Target(), 1011 strip_cdata=False) 1012 1013 parser.feed(_bytes('<root>A<a><![CDATA[ca]]></a>B</root>')) 1014 done = parser.close() 1015 1016 self.assertEqual("DONE", done) 1017 self.assertEqual(["start-root", "data-A", "start-a", 1018 "data-ca", "end-a", "data-B", "end-root"], 1019 events) 1020
1021 - def test_parser_target_recover(self):
1022 events = [] 1023 class Target(object): 1024 def start(self, tag, attrib): 1025 events.append("start-" + tag)
1026 def end(self, tag): 1027 events.append("end-" + tag) 1028 def data(self, data): 1029 events.append("data-" + data) 1030 def close(self): 1031 events.append("close") 1032 return "DONE" 1033 1034 parser = self.etree.XMLParser(target=Target(), 1035 recover=True) 1036 1037 parser.feed(_bytes('<root>A<a>ca</a>B</not-root>')) 1038 done = parser.close() 1039 1040 self.assertEqual("DONE", done) 1041 self.assertEqual(["start-root", "data-A", "start-a", 1042 "data-ca", "end-a", "data-B", 1043 "end-root", "close"], 1044 events) 1045
1046 - def test_iterwalk_tag(self):
1047 iterwalk = self.etree.iterwalk 1048 root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>')) 1049 1050 iterator = iterwalk(root, tag="b", events=('start', 'end')) 1051 events = list(iterator) 1052 self.assertEqual( 1053 [('start', root[0]), ('end', root[0])], 1054 events)
1055
1056 - def test_iterwalk_tag_all(self):
1057 iterwalk = self.etree.iterwalk 1058 root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>')) 1059 1060 iterator = iterwalk(root, tag="*", events=('start', 'end')) 1061 events = list(iterator) 1062 self.assertEqual( 1063 8, 1064 len(events))
1065
1066 - def test_iterwalk(self):
1067 iterwalk = self.etree.iterwalk 1068 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1069 1070 events = list(iterwalk(root)) 1071 self.assertEqual( 1072 [('end', root[0]), ('end', root[1]), ('end', root)], 1073 events)
1074
1075 - def test_iterwalk_start(self):
1076 iterwalk = self.etree.iterwalk 1077 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1078 1079 iterator = iterwalk(root, events=('start',)) 1080 events = list(iterator) 1081 self.assertEqual( 1082 [('start', root), ('start', root[0]), ('start', root[1])], 1083 events)
1084
1085 - def test_iterwalk_start_end(self):
1086 iterwalk = self.etree.iterwalk 1087 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1088 1089 iterator = iterwalk(root, events=('start','end')) 1090 events = list(iterator) 1091 self.assertEqual( 1092 [('start', root), ('start', root[0]), ('end', root[0]), 1093 ('start', root[1]), ('end', root[1]), ('end', root)], 1094 events)
1095
1096 - def test_iterwalk_clear(self):
1097 iterwalk = self.etree.iterwalk 1098 root = self.etree.XML(_bytes('<a><b></b><c/></a>')) 1099 1100 iterator = iterwalk(root) 1101 for event, elem in iterator: 1102 elem.clear() 1103 1104 self.assertEqual(0, 1105 len(root))
1106
1107 - def test_iterwalk_attrib_ns(self):
1108 iterwalk = self.etree.iterwalk 1109 root = self.etree.XML(_bytes('<a xmlns="ns1"><b><c xmlns="ns2"/></b></a>')) 1110 1111 attr_name = '{testns}bla' 1112 events = [] 1113 iterator = iterwalk(root, events=('start','end','start-ns','end-ns')) 1114 for event, elem in iterator: 1115 events.append(event) 1116 if event == 'start': 1117 if elem.tag != '{ns1}a': 1118 elem.set(attr_name, 'value') 1119 1120 self.assertEqual( 1121 ['start-ns', 'start', 'start', 'start-ns', 'start', 1122 'end', 'end-ns', 'end', 'end', 'end-ns'], 1123 events) 1124 1125 self.assertEqual( 1126 None, 1127 root.get(attr_name)) 1128 self.assertEqual( 1129 'value', 1130 root[0].get(attr_name))
1131
1132 - def test_iterwalk_getiterator(self):
1133 iterwalk = self.etree.iterwalk 1134 root = self.etree.XML(_bytes('<a><b><d/></b><c/></a>')) 1135 1136 counts = [] 1137 for event, elem in iterwalk(root): 1138 counts.append(len(list(elem.getiterator()))) 1139 self.assertEqual( 1140 [1,2,1,4], 1141 counts)
1142
1143 - def test_resolve_string_dtd(self):
1144 parse = self.etree.parse 1145 parser = self.etree.XMLParser(dtd_validation=True) 1146 assertEqual = self.assertEqual 1147 test_url = _str("__nosuch.dtd") 1148 1149 class MyResolver(self.etree.Resolver): 1150 def resolve(self, url, id, context): 1151 assertEqual(url, test_url) 1152 return self.resolve_string( 1153 _str('''<!ENTITY myentity "%s"> 1154 <!ELEMENT doc ANY>''') % url, context)
1155 1156 parser.resolvers.add(MyResolver()) 1157 1158 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1159 tree = parse(StringIO(xml), parser) 1160 root = tree.getroot() 1161 self.assertEqual(root.text, test_url) 1162
1163 - def test_resolve_bytes_dtd(self):
1164 parse = self.etree.parse 1165 parser = self.etree.XMLParser(dtd_validation=True) 1166 assertEqual = self.assertEqual 1167 test_url = _str("__nosuch.dtd") 1168 1169 class MyResolver(self.etree.Resolver): 1170 def resolve(self, url, id, context): 1171 assertEqual(url, test_url) 1172 return self.resolve_string( 1173 (_str('''<!ENTITY myentity "%s"> 1174 <!ELEMENT doc ANY>''') % url).encode('utf-8'), 1175 context)
1176 1177 parser.resolvers.add(MyResolver()) 1178 1179 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1180 tree = parse(StringIO(xml), parser) 1181 root = tree.getroot() 1182 self.assertEqual(root.text, test_url) 1183
1184 - def test_resolve_filelike_dtd(self):
1185 parse = self.etree.parse 1186 parser = self.etree.XMLParser(dtd_validation=True) 1187 assertEqual = self.assertEqual 1188 test_url = _str("__nosuch.dtd") 1189 1190 class MyResolver(self.etree.Resolver): 1191 def resolve(self, url, id, context): 1192 assertEqual(url, test_url) 1193 return self.resolve_file( 1194 SillyFileLike( 1195 _str('''<!ENTITY myentity "%s"> 1196 <!ELEMENT doc ANY>''') % url), context)
1197 1198 parser.resolvers.add(MyResolver()) 1199 1200 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1201 tree = parse(StringIO(xml), parser) 1202 root = tree.getroot() 1203 self.assertEqual(root.text, test_url) 1204
1205 - def test_resolve_filename_dtd(self):
1206 parse = self.etree.parse 1207 parser = self.etree.XMLParser(attribute_defaults=True) 1208 assertEqual = self.assertEqual 1209 test_url = _str("__nosuch.dtd") 1210 1211 class MyResolver(self.etree.Resolver): 1212 def resolve(self, url, id, context): 1213 assertEqual(url, test_url) 1214 return self.resolve_filename( 1215 fileInTestDir('test.dtd'), context)
1216 1217 parser.resolvers.add(MyResolver()) 1218 1219 xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url 1220 tree = parse(StringIO(xml), parser) 1221 root = tree.getroot() 1222 self.assertEqual( 1223 root.attrib, {'default': 'valueA'}) 1224 self.assertEqual( 1225 root[0].attrib, {'default': 'valueB'}) 1226
1227 - def test_resolve_filename_dtd_relative(self):
1228 parse = self.etree.parse 1229 parser = self.etree.XMLParser(attribute_defaults=True) 1230 assertEqual = self.assertEqual 1231 test_url = _str("__nosuch.dtd") 1232 1233 class MyResolver(self.etree.Resolver): 1234 def resolve(self, url, id, context): 1235 assertEqual(url, fileUrlInTestDir(test_url)) 1236 return self.resolve_filename( 1237 fileUrlInTestDir('test.dtd'), context)
1238 1239 parser.resolvers.add(MyResolver()) 1240 1241 xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url 1242 tree = parse(StringIO(xml), parser, 1243 base_url=fileUrlInTestDir('__test.xml')) 1244 root = tree.getroot() 1245 self.assertEqual( 1246 root.attrib, {'default': 'valueA'}) 1247 self.assertEqual( 1248 root[0].attrib, {'default': 'valueB'}) 1249
1250 - def test_resolve_file_dtd(self):
1251 parse = self.etree.parse 1252 parser = self.etree.XMLParser(attribute_defaults=True) 1253 assertEqual = self.assertEqual 1254 test_url = _str("__nosuch.dtd") 1255 1256 class MyResolver(self.etree.Resolver): 1257 def resolve(self, url, id, context): 1258 assertEqual(url, test_url) 1259 return self.resolve_file( 1260 open(fileInTestDir('test.dtd'), 'rb'), context)
1261 1262 parser.resolvers.add(MyResolver()) 1263 1264 xml = _str('<!DOCTYPE a SYSTEM "%s"><a><b/></a>') % test_url 1265 tree = parse(StringIO(xml), parser) 1266 root = tree.getroot() 1267 self.assertEqual( 1268 root.attrib, {'default': 'valueA'}) 1269 self.assertEqual( 1270 root[0].attrib, {'default': 'valueB'}) 1271
1272 - def test_resolve_empty(self):
1273 parse = self.etree.parse 1274 parser = self.etree.XMLParser(load_dtd=True) 1275 assertEqual = self.assertEqual 1276 test_url = _str("__nosuch.dtd") 1277 1278 class check(object): 1279 resolved = False
1280 1281 class MyResolver(self.etree.Resolver): 1282 def resolve(self, url, id, context): 1283 assertEqual(url, test_url) 1284 check.resolved = True 1285 return self.resolve_empty(context) 1286 1287 parser.resolvers.add(MyResolver()) 1288 1289 xml = _str('<!DOCTYPE doc SYSTEM "%s"><doc>&myentity;</doc>') % test_url 1290 self.assertRaises(etree.XMLSyntaxError, parse, StringIO(xml), parser) 1291 self.assertTrue(check.resolved) 1292
1293 - def test_resolve_error(self):
1294 parse = self.etree.parse 1295 parser = self.etree.XMLParser(dtd_validation=True) 1296 1297 class _LocalException(Exception): 1298 pass
1299 1300 class MyResolver(self.etree.Resolver): 1301 def resolve(self, url, id, context): 1302 raise _LocalException 1303 1304 parser.resolvers.add(MyResolver()) 1305 1306 xml = '<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>' 1307 self.assertRaises(_LocalException, parse, BytesIO(xml), parser) 1308 1309 if etree.LIBXML_VERSION > (2,6,20):
1310 - def test_entity_parse(self):
1311 parse = self.etree.parse 1312 tostring = self.etree.tostring 1313 parser = self.etree.XMLParser(resolve_entities=False) 1314 Entity = self.etree.Entity 1315 1316 xml = _bytes('<!DOCTYPE doc SYSTEM "test"><doc>&myentity;</doc>') 1317 tree = parse(BytesIO(xml), parser) 1318 root = tree.getroot() 1319 self.assertEqual(root[0].tag, Entity) 1320 self.assertEqual(root[0].text, "&myentity;") 1321 self.assertEqual(root[0].tail, None) 1322 self.assertEqual(root[0].name, "myentity") 1323 1324 self.assertEqual(_bytes('<doc>&myentity;</doc>'), 1325 tostring(root))
1326
1327 - def test_entity_restructure(self):
1328 xml = _bytes('''<!DOCTYPE root [ <!ENTITY nbsp "&#160;"> ]> 1329 <root> 1330 <child1/> 1331 <child2/> 1332 <child3>&nbsp;</child3> 1333 </root>''') 1334 1335 parser = self.etree.XMLParser(resolve_entities=False) 1336 root = etree.fromstring(xml, parser) 1337 self.assertEqual([ el.tag for el in root ], 1338 ['child1', 'child2', 'child3']) 1339 1340 root[0] = root[-1] 1341 self.assertEqual([ el.tag for el in root ], 1342 ['child3', 'child2']) 1343 self.assertEqual(root[0][0].text, '&nbsp;') 1344 self.assertEqual(root[0][0].name, 'nbsp')
1345
1346 - def test_entity_append(self):
1347 Entity = self.etree.Entity 1348 Element = self.etree.Element 1349 tostring = self.etree.tostring 1350 1351 root = Element("root") 1352 root.append( Entity("test") ) 1353 1354 self.assertEqual(root[0].tag, Entity) 1355 self.assertEqual(root[0].text, "&test;") 1356 self.assertEqual(root[0].tail, None) 1357 self.assertEqual(root[0].name, "test") 1358 1359 self.assertEqual(_bytes('<root>&test;</root>'), 1360 tostring(root))
1361
1362 - def test_entity_values(self):
1363 Entity = self.etree.Entity 1364 self.assertEqual(Entity("test").text, '&test;') 1365 self.assertEqual(Entity("#17683").text, '&#17683;') 1366 self.assertEqual(Entity("#x1768").text, '&#x1768;') 1367 self.assertEqual(Entity("#x98AF").text, '&#x98AF;')
1368
1369 - def test_entity_error(self):
1370 Entity = self.etree.Entity 1371 self.assertRaises(ValueError, Entity, 'a b c') 1372 self.assertRaises(ValueError, Entity, 'a,b') 1373 self.assertRaises(ValueError, Entity, 'a\0b') 1374 self.assertRaises(ValueError, Entity, '#abc') 1375 self.assertRaises(ValueError, Entity, '#xxyz')
1376
1377 - def test_cdata(self):
1378 CDATA = self.etree.CDATA 1379 Element = self.etree.Element 1380 tostring = self.etree.tostring 1381 1382 root = Element("root") 1383 root.text = CDATA('test') 1384 1385 self.assertEqual('test', 1386 root.text) 1387 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 1388 tostring(root))
1389
1390 - def test_cdata_type(self):
1391 CDATA = self.etree.CDATA 1392 Element = self.etree.Element 1393 root = Element("root") 1394 1395 root.text = CDATA("test") 1396 self.assertEqual('test', root.text) 1397 1398 root.text = CDATA(_str("test")) 1399 self.assertEqual('test', root.text) 1400 1401 self.assertRaises(TypeError, CDATA, 1)
1402
1403 - def test_cdata_errors(self):
1404 CDATA = self.etree.CDATA 1405 Element = self.etree.Element 1406 1407 root = Element("root") 1408 cdata = CDATA('test') 1409 1410 self.assertRaises(TypeError, 1411 setattr, root, 'tail', cdata) 1412 self.assertRaises(TypeError, 1413 root.set, 'attr', cdata) 1414 self.assertRaises(TypeError, 1415 operator.setitem, root.attrib, 'attr', cdata)
1416
1417 - def test_cdata_parser(self):
1418 tostring = self.etree.tostring 1419 parser = self.etree.XMLParser(strip_cdata=False) 1420 root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser) 1421 1422 self.assertEqual('test', root.text) 1423 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 1424 tostring(root))
1425
1426 - def test_cdata_xpath(self):
1427 tostring = self.etree.tostring 1428 parser = self.etree.XMLParser(strip_cdata=False) 1429 root = self.etree.XML(_bytes('<root><![CDATA[test]]></root>'), parser) 1430 self.assertEqual(_bytes('<root><![CDATA[test]]></root>'), 1431 tostring(root)) 1432 1433 self.assertEqual(['test'], root.xpath('//text()'))
1434 1435 # TypeError in etree, AssertionError in ElementTree;
1436 - def test_setitem_assert(self):
1437 Element = self.etree.Element 1438 SubElement = self.etree.SubElement 1439 1440 a = Element('a') 1441 b = SubElement(a, 'b') 1442 1443 self.assertRaises(TypeError, 1444 a.__setitem__, 0, 'foo')
1445
1446 - def test_append_error(self):
1447 Element = self.etree.Element 1448 root = Element('root') 1449 # raises AssertionError in ElementTree 1450 self.assertRaises(TypeError, root.append, None) 1451 self.assertRaises(TypeError, root.extend, [None]) 1452 self.assertRaises(TypeError, root.extend, [Element('one'), None]) 1453 self.assertEqual('one', root[0].tag)
1454
1455 - def test_append_recursive_error(self):
1456 Element = self.etree.Element 1457 SubElement = self.etree.SubElement 1458 root = Element('root') 1459 self.assertRaises(ValueError, root.append, root) 1460 child = SubElement(root, 'child') 1461 self.assertRaises(ValueError, child.append, root) 1462 child2 = SubElement(child, 'child2') 1463 self.assertRaises(ValueError, child2.append, root) 1464 self.assertRaises(ValueError, child2.append, child) 1465 self.assertEqual('child2', root[0][0].tag)
1466
1467 - def test_addnext(self):
1468 Element = self.etree.Element 1469 SubElement = self.etree.SubElement 1470 root = Element('root') 1471 SubElement(root, 'a') 1472 SubElement(root, 'b') 1473 1474 self.assertEqual(['a', 'b'], 1475 [c.tag for c in root]) 1476 root[1].addnext(root[0]) 1477 self.assertEqual(['b', 'a'], 1478 [c.tag for c in root])
1479
1480 - def test_addprevious(self):
1481 Element = self.etree.Element 1482 SubElement = self.etree.SubElement 1483 root = Element('root') 1484 SubElement(root, 'a') 1485 SubElement(root, 'b') 1486 1487 self.assertEqual(['a', 'b'], 1488 [c.tag for c in root]) 1489 root[0].addprevious(root[1]) 1490 self.assertEqual(['b', 'a'], 1491 [c.tag for c in root])
1492
1493 - def test_addnext_cycle(self):
1494 Element = self.etree.Element 1495 SubElement = self.etree.SubElement 1496 root = Element('root') 1497 a = SubElement(root, 'a') 1498 b = SubElement(a, 'b') 1499 # appending parent as sibling is forbidden 1500 self.assertRaises(ValueError, b.addnext, a) 1501 self.assertEqual(['a'], [c.tag for c in root]) 1502 self.assertEqual(['b'], [c.tag for c in a])
1503
1504 - def test_addprevious_cycle(self):
1505 Element = self.etree.Element 1506 SubElement = self.etree.SubElement 1507 root = Element('root') 1508 a = SubElement(root, 'a') 1509 b = SubElement(a, 'b') 1510 # appending parent as sibling is forbidden 1511 self.assertRaises(ValueError, b.addprevious, a) 1512 self.assertEqual(['a'], [c.tag for c in root]) 1513 self.assertEqual(['b'], [c.tag for c in a])
1514
1515 - def test_addnext_cycle_long(self):
1516 Element = self.etree.Element 1517 SubElement = self.etree.SubElement 1518 root = Element('root') 1519 a = SubElement(root, 'a') 1520 b = SubElement(a, 'b') 1521 c = SubElement(b, 'c') 1522 # appending parent as sibling is forbidden 1523 self.assertRaises(ValueError, c.addnext, a)
1524
1525 - def test_addprevious_cycle_long(self):
1526 Element = self.etree.Element 1527 SubElement = self.etree.SubElement 1528 root = Element('root') 1529 a = SubElement(root, 'a') 1530 b = SubElement(a, 'b') 1531 c = SubElement(b, 'c') 1532 # appending parent as sibling is forbidden 1533 self.assertRaises(ValueError, c.addprevious, a)
1534
1535 - def test_addprevious_noops(self):
1536 Element = self.etree.Element 1537 SubElement = self.etree.SubElement 1538 root = Element('root') 1539 a = SubElement(root, 'a') 1540 b = SubElement(root, 'b') 1541 a.addprevious(a) 1542 self.assertEqual('a', root[0].tag) 1543 self.assertEqual('b', root[1].tag) 1544 b.addprevious(b) 1545 self.assertEqual('a', root[0].tag) 1546 self.assertEqual('b', root[1].tag) 1547 b.addprevious(a) 1548 self.assertEqual('a', root[0].tag) 1549 self.assertEqual('b', root[1].tag)
1550
1551 - def test_addnext_noops(self):
1552 Element = self.etree.Element 1553 SubElement = self.etree.SubElement 1554 root = Element('root') 1555 a = SubElement(root, 'a') 1556 b = SubElement(root, 'b') 1557 a.addnext(a) 1558 self.assertEqual('a', root[0].tag) 1559 self.assertEqual('b', root[1].tag) 1560 b.addnext(b) 1561 self.assertEqual('a', root[0].tag) 1562 self.assertEqual('b', root[1].tag) 1563 a.addnext(b) 1564 self.assertEqual('a', root[0].tag) 1565 self.assertEqual('b', root[1].tag)
1566
1567 - def test_addnext_root(self):
1568 Element = self.etree.Element 1569 a = Element('a') 1570 b = Element('b') 1571 self.assertRaises(TypeError, a.addnext, b)
1572
1573 - def test_addprevious_pi(self):
1574 Element = self.etree.Element 1575 SubElement = self.etree.SubElement 1576 PI = self.etree.PI 1577 root = Element('root') 1578 SubElement(root, 'a') 1579 pi = PI('TARGET', 'TEXT') 1580 pi.tail = "TAIL" 1581 1582 self.assertEqual(_bytes('<root><a></a></root>'), 1583 self._writeElement(root)) 1584 root[0].addprevious(pi) 1585 self.assertEqual(_bytes('<root><?TARGET TEXT?>TAIL<a></a></root>'), 1586 self._writeElement(root))
1587
1588 - def test_addprevious_root_pi(self):
1589 Element = self.etree.Element 1590 PI = self.etree.PI 1591 root = Element('root') 1592 pi = PI('TARGET', 'TEXT') 1593 pi.tail = "TAIL" 1594 1595 self.assertEqual(_bytes('<root></root>'), 1596 self._writeElement(root)) 1597 root.addprevious(pi) 1598 self.assertEqual(_bytes('<?TARGET TEXT?>\n<root></root>'), 1599 self._writeElement(root))
1600
1601 - def test_addnext_pi(self):
1602 Element = self.etree.Element 1603 SubElement = self.etree.SubElement 1604 PI = self.etree.PI 1605 root = Element('root') 1606 SubElement(root, 'a') 1607 pi = PI('TARGET', 'TEXT') 1608 pi.tail = "TAIL" 1609 1610 self.assertEqual(_bytes('<root><a></a></root>'), 1611 self._writeElement(root)) 1612 root[0].addnext(pi) 1613 self.assertEqual(_bytes('<root><a></a><?TARGET TEXT?>TAIL</root>'), 1614 self._writeElement(root))
1615
1616 - def test_addnext_root_pi(self):
1617 Element = self.etree.Element 1618 PI = self.etree.PI 1619 root = Element('root') 1620 pi = PI('TARGET', 'TEXT') 1621 pi.tail = "TAIL" 1622 1623 self.assertEqual(_bytes('<root></root>'), 1624 self._writeElement(root)) 1625 root.addnext(pi) 1626 self.assertEqual(_bytes('<root></root>\n<?TARGET TEXT?>'), 1627 self._writeElement(root))
1628
1629 - def test_addnext_comment(self):
1630 Element = self.etree.Element 1631 SubElement = self.etree.SubElement 1632 Comment = self.etree.Comment 1633 root = Element('root') 1634 SubElement(root, 'a') 1635 comment = Comment('TEXT ') 1636 comment.tail = "TAIL" 1637 1638 self.assertEqual(_bytes('<root><a></a></root>'), 1639 self._writeElement(root)) 1640 root[0].addnext(comment) 1641 self.assertEqual(_bytes('<root><a></a><!--TEXT -->TAIL</root>'), 1642 self._writeElement(root))
1643
1644 - def test_addnext_root_comment(self):
1645 Element = self.etree.Element 1646 Comment = self.etree.Comment 1647 root = Element('root') 1648 comment = Comment('TEXT ') 1649 comment.tail = "TAIL" 1650 1651 self.assertEqual(_bytes('<root></root>'), 1652 self._writeElement(root)) 1653 root.addnext(comment) 1654 self.assertEqual(_bytes('<root></root>\n<!--TEXT -->'), 1655 self._writeElement(root))
1656
1657 - def test_addprevious_comment(self):
1658 Element = self.etree.Element 1659 SubElement = self.etree.SubElement 1660 Comment = self.etree.Comment 1661 root = Element('root') 1662 SubElement(root, 'a') 1663 comment = Comment('TEXT ') 1664 comment.tail = "TAIL" 1665 1666 self.assertEqual(_bytes('<root><a></a></root>'), 1667 self._writeElement(root)) 1668 root[0].addprevious(comment) 1669 self.assertEqual(_bytes('<root><!--TEXT -->TAIL<a></a></root>'), 1670 self._writeElement(root))
1671
1672 - def test_addprevious_root_comment(self):
1673 Element = self.etree.Element 1674 Comment = self.etree.Comment 1675 root = Element('root') 1676 comment = Comment('TEXT ') 1677 comment.tail = "TAIL" 1678 1679 self.assertEqual(_bytes('<root></root>'), 1680 self._writeElement(root)) 1681 root.addprevious(comment) 1682 self.assertEqual(_bytes('<!--TEXT -->\n<root></root>'), 1683 self._writeElement(root))
1684 1685 # ET's Elements have items() and key(), but not values()
1686 - def test_attribute_values(self):
1687 XML = self.etree.XML 1688 1689 root = XML(_bytes('<doc alpha="Alpha" beta="Beta" gamma="Gamma"/>')) 1690 values = root.values() 1691 values.sort() 1692 self.assertEqual(['Alpha', 'Beta', 'Gamma'], values)
1693 1694 # gives error in ElementTree
1695 - def test_comment_empty(self):
1696 Element = self.etree.Element 1697 Comment = self.etree.Comment 1698 1699 a = Element('a') 1700 a.append(Comment()) 1701 self.assertEqual( 1702 _bytes('<a><!----></a>'), 1703 self._writeElement(a))
1704 1705 # ElementTree ignores comments
1706 - def test_comment_parse_empty(self):
1707 ElementTree = self.etree.ElementTree 1708 tostring = self.etree.tostring 1709 1710 xml = _bytes('<a><b/><!----><c/></a>') 1711 f = BytesIO(xml) 1712 doc = ElementTree(file=f) 1713 a = doc.getroot() 1714 self.assertEqual( 1715 '', 1716 a[1].text) 1717 self.assertEqual( 1718 xml, 1719 tostring(a))
1720 1721 # ElementTree ignores comments
1722 - def test_comment_no_proxy_yet(self):
1723 ElementTree = self.etree.ElementTree 1724 1725 f = BytesIO('<a><b></b><!-- hoi --><c></c></a>') 1726 doc = ElementTree(file=f) 1727 a = doc.getroot() 1728 self.assertEqual( 1729 ' hoi ', 1730 a[1].text)
1731 1732 # does not raise an exception in ElementTree
1733 - def test_comment_immutable(self):
1734 Element = self.etree.Element 1735 Comment = self.etree.Comment 1736 1737 c = Comment() 1738 el = Element('myel') 1739 1740 self.assertRaises(TypeError, c.append, el) 1741 self.assertRaises(TypeError, c.insert, 0, el) 1742 self.assertRaises(TypeError, c.set, "myattr", "test")
1743
1744 - def test_comment_immutable_attrib(self):
1745 c = self.etree.Comment() 1746 self.assertEqual(0, len(c.attrib)) 1747 1748 self.assertFalse(c.attrib.__contains__('nope')) 1749 self.assertFalse('nope' in c.attrib) 1750 self.assertFalse('nope' in c.attrib.keys()) 1751 self.assertFalse('nope' in c.attrib.values()) 1752 self.assertFalse(('nope', 'huhu') in c.attrib.items()) 1753 1754 self.assertEqual([], list(c.attrib)) 1755 self.assertEqual([], list(c.attrib.keys())) 1756 self.assertEqual([], list(c.attrib.items())) 1757 self.assertEqual([], list(c.attrib.values())) 1758 self.assertEqual([], list(c.attrib.iterkeys())) 1759 self.assertEqual([], list(c.attrib.iteritems())) 1760 self.assertEqual([], list(c.attrib.itervalues())) 1761 1762 self.assertEqual('HUHU', c.attrib.pop('nope', 'HUHU')) 1763 self.assertRaises(KeyError, c.attrib.pop, 'nope') 1764 1765 self.assertRaises(KeyError, c.attrib.__getitem__, 'only') 1766 self.assertRaises(KeyError, c.attrib.__getitem__, 'names') 1767 self.assertRaises(KeyError, c.attrib.__getitem__, 'nope') 1768 self.assertRaises(KeyError, c.attrib.__setitem__, 'nope', 'yep') 1769 self.assertRaises(KeyError, c.attrib.__delitem__, 'nope')
1770 1771 # test passing 'None' to dump()
1772 - def test_dump_none(self):
1773 self.assertRaises(TypeError, self.etree.dump, None)
1774
1775 - def test_prefix(self):
1776 ElementTree = self.etree.ElementTree 1777 1778 f = BytesIO('<a xmlns:foo="http://www.infrae.com/ns/1"><foo:b/></a>') 1779 doc = ElementTree(file=f) 1780 a = doc.getroot() 1781 self.assertEqual( 1782 None, 1783 a.prefix) 1784 self.assertEqual( 1785 'foo', 1786 a[0].prefix)
1787
1788 - def test_prefix_default_ns(self):
1789 ElementTree = self.etree.ElementTree 1790 1791 f = BytesIO('<a xmlns="http://www.infrae.com/ns/1"><b/></a>') 1792 doc = ElementTree(file=f) 1793 a = doc.getroot() 1794 self.assertEqual( 1795 None, 1796 a.prefix) 1797 self.assertEqual( 1798 None, 1799 a[0].prefix)
1800
1801 - def test_getparent(self):
1802 Element = self.etree.Element 1803 SubElement = self.etree.SubElement 1804 1805 a = Element('a') 1806 b = SubElement(a, 'b') 1807 c = SubElement(a, 'c') 1808 d = SubElement(b, 'd') 1809 self.assertEqual( 1810 None, 1811 a.getparent()) 1812 self.assertEqual( 1813 a, 1814 b.getparent()) 1815 self.assertEqual( 1816 b.getparent(), 1817 c.getparent()) 1818 self.assertEqual( 1819 b, 1820 d.getparent())
1821
1822 - def test_iterchildren(self):
1823 XML = self.etree.XML 1824 1825 root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>')) 1826 result = [] 1827 for el in root.iterchildren(): 1828 result.append(el.tag) 1829 self.assertEqual(['one', 'two', 'three'], result)
1830
1831 - def test_iterchildren_reversed(self):
1832 XML = self.etree.XML 1833 1834 root = XML(_bytes('<doc><one/><two>Two</two>Hm<three/></doc>')) 1835 result = [] 1836 for el in root.iterchildren(reversed=True): 1837 result.append(el.tag) 1838 self.assertEqual(['three', 'two', 'one'], result)
1839
1840 - def test_iterchildren_tag(self):
1841 XML = self.etree.XML 1842 1843 root = XML(_bytes('<doc><one/><two>Two</two>Hm<two>Bla</two></doc>')) 1844 result = [] 1845 <