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

Source Code for Module lxml.tests.test_xpathevaluator

  1  # -*- coding: utf-8 -*- 
  2   
  3  """ 
  4  Test cases related to XPath evaluation and the XPath class 
  5  """ 
  6   
  7  import unittest, doctest 
  8  from StringIO import StringIO 
  9   
 10  from common_imports import etree, HelperTestCase 
 11   
12 -class ETreeXPathTestCase(HelperTestCase):
13 """XPath tests etree""" 14
15 - def test_xpath_boolean(self):
16 tree = self.parse('<a><b></b><b></b></a>') 17 self.assert_(tree.xpath('boolean(/a/b)')) 18 self.assert_(not tree.xpath('boolean(/a/c)'))
19
20 - def test_xpath_number(self):
21 tree = self.parse('<a>1</a>') 22 self.assertEquals(1., 23 tree.xpath('number(/a)')) 24 tree = self.parse('<a>A</a>') 25 actual = str(tree.xpath('number(/a)')) 26 expected = ['nan', '1.#qnan', 'nanq'] 27 if not actual.lower() in expected: 28 self.fail('Expected a NAN value, got %s' % actual)
29
30 - def test_xpath_string(self):
31 tree = self.parse('<a>Foo</a>') 32 self.assertEquals('Foo', 33 tree.xpath('string(/a/text())'))
34
35 - def test_xpath_document_root(self):
36 tree = self.parse('<a><b/></a>') 37 self.assertEquals([], 38 tree.xpath('/'))
39
40 - def test_xpath_namespace(self):
41 tree = self.parse('<a xmlns="test" xmlns:p="myURI"/>') 42 self.assert_((None, "test") in tree.xpath('namespace::*')) 43 self.assert_(('p', 'myURI') in tree.xpath('namespace::*'))
44
46 tree = self.parse('<a/>') 47 self.assertEquals([('xml', 'http://www.w3.org/XML/1998/namespace')], 48 tree.xpath('namespace::*'))
49
50 - def test_xpath_list_elements(self):
51 tree = self.parse('<a><b>Foo</b><b>Bar</b></a>') 52 root = tree.getroot() 53 self.assertEquals([root[0], root[1]], 54 tree.xpath('/a/b'))
55
56 - def test_xpath_list_nothing(self):
57 tree = self.parse('<a><b/></a>') 58 self.assertEquals([], 59 tree.xpath('/a/c')) 60 # this seems to pass a different code path, also should return nothing 61 self.assertEquals([], 62 tree.xpath('/a/c/text()'))
63
64 - def test_xpath_list_text(self):
65 tree = self.parse('<a><b>Foo</b><b>Bar</b></a>') 66 root = tree.getroot() 67 self.assertEquals(['Foo', 'Bar'], 68 tree.xpath('/a/b/text()'))
69
71 tree = self.parse('<a b="B" c="C"/>') 72 self.assertEquals(['B'], 73 tree.xpath('/a/@b'))
74
75 - def test_xpath_list_comment(self):
76 tree = self.parse('<a><!-- Foo --></a>') 77 self.assertEquals(['<!-- Foo -->'], 78 map(repr, tree.xpath('/a/node()')))
79
80 - def test_rel_xpath_boolean(self):
81 root = etree.XML('<a><b><c/></b></a>') 82 el = root[0] 83 self.assert_(el.xpath('boolean(c)')) 84 self.assert_(not el.xpath('boolean(d)'))
85
87 tree = self.parse('<a><c><b>Foo</b><b>Bar</b></c><c><b>Hey</b></c></a>') 88 root = tree.getroot() 89 c = root[0] 90 self.assertEquals([c[0], c[1]], 91 c.xpath('b')) 92 self.assertEquals([c[0], c[1], root[1][0]], 93 c.xpath('//b'))
94
95 - def test_xpath_ns(self):
96 tree = self.parse('<a xmlns="uri:a"><b></b></a>') 97 root = tree.getroot() 98 self.assertEquals( 99 [root[0]], 100 tree.xpath('//foo:b', {'foo': 'uri:a'})) 101 self.assertEquals( 102 [], 103 tree.xpath('//foo:b', {'foo': 'uri:c'})) 104 self.assertEquals( 105 [root[0]], 106 root.xpath('//baz:b', {'baz': 'uri:a'}))
107
108 - def test_xpath_ns_none(self):
109 tree = self.parse('<a xmlns="uri:a"><b></b></a>') 110 root = tree.getroot() 111 self.assertRaises( 112 TypeError, 113 root.xpath, '//b', {None: 'uri:a'})
114
115 - def test_xpath_error(self):
116 tree = self.parse('<a/>') 117 self.assertRaises(SyntaxError, tree.xpath, '\\fad')
118
119 - def test_elementtree_getpath(self):
120 a = etree.Element("a") 121 b = etree.SubElement(a, "b") 122 c = etree.SubElement(a, "c") 123 d1 = etree.SubElement(c, "d") 124 d2 = etree.SubElement(c, "d") 125 126 tree = etree.ElementTree(a) 127 self.assertEqual('/a/c/d', 128 tree.getpath(d2)[:6]) 129 self.assertEqual([d2], 130 tree.xpath(tree.getpath(d2)))
131
133 a = etree.Element("a") 134 b = etree.SubElement(a, "b") 135 c = etree.SubElement(a, "c") 136 d1 = etree.SubElement(c, "d") 137 d2 = etree.SubElement(c, "d") 138 139 tree = etree.ElementTree(c) 140 self.assertEqual('/c/d', 141 tree.getpath(d2)[:4]) 142 self.assertEqual([d2], 143 tree.xpath(tree.getpath(d2)))
144
145 - def test_xpath_evaluator(self):
146 tree = self.parse('<a><b><c></c></b></a>') 147 e = etree.XPathEvaluator(tree) 148 root = tree.getroot() 149 self.assertEquals( 150 [root], 151 e.evaluate('//a'))
152
154 tree = self.parse('<a><b><c></c></b></a>') 155 child_tree = etree.ElementTree(tree.getroot()[0]) 156 e = etree.XPathEvaluator(child_tree) 157 self.assertEquals( 158 [], 159 e.evaluate('a')) 160 root = child_tree.getroot() 161 self.assertEquals( 162 [root[0]], 163 e.evaluate('c'))
164
166 tree = self.parse('<a><b><c></c></b></a>') 167 root = tree.getroot() 168 e = etree.XPathEvaluator(root[0]) 169 self.assertEquals( 170 [root[0][0]], 171 e.evaluate('c'))
172
173 - def test_xpath_extensions(self):
174 def foo(evaluator, a): 175 return 'hello %s' % a
176 extension = {(None, 'foo'): foo} 177 tree = self.parse('<a><b></b></a>') 178 e = etree.XPathEvaluator(tree, None, [extension]) 179 self.assertEquals( 180 "hello you", e.evaluate("foo('you')"))
181
182 - def test_xpath_extensions_wrong_args(self):
183 def foo(evaluator, a, b): 184 return "hello %s and %s" % (a, b)
185 extension = {(None, 'foo'): foo} 186 tree = self.parse('<a><b></b></a>') 187 e = etree.XPathEvaluator(tree, extensions=[extension]) 188 self.assertRaises(TypeError, e.evaluate, "foo('you')") 189
190 - def test_xpath_extensions_error(self):
191 def foo(evaluator, a): 192 return 1/0
193 extension = {(None, 'foo'): foo} 194 tree = self.parse('<a/>') 195 e = etree.XPathEvaluator(tree, None, [extension]) 196 self.assertRaises(ZeroDivisionError, e.evaluate, "foo('test')") 197
198 - def test_xpath_extensions_nodes(self):
199 def f(evaluator, arg): 200 r = etree.Element('results') 201 b = etree.SubElement(r, 'result') 202 b.text = 'Hoi' 203 b = etree.SubElement(r, 'result') 204 b.text = 'Dag' 205 return r
206 207 x = self.parse('<a/>') 208 e = etree.XPathEvaluator(x, None, [{(None, 'foo'): f}]) 209 r = e.evaluate("foo('World')/result") 210 self.assertEquals(2, len(r)) 211 self.assertEquals('Hoi', r[0].text) 212 self.assertEquals('Dag', r[1].text) 213
214 - def test_xpath_extensions_nodes_append(self):
215 def f(evaluator, nodes): 216 r = etree.SubElement(nodes[0], 'results') 217 b = etree.SubElement(r, 'result') 218 b.text = 'Hoi' 219 b = etree.SubElement(r, 'result') 220 b.text = 'Dag' 221 return r
222 223 x = self.parse('<a/>') 224 e = etree.XPathEvaluator(x, None, [{(None, 'foo'): f}]) 225 r = e.evaluate("foo(/*)/result") 226 self.assertEquals(2, len(r)) 227 self.assertEquals('Hoi', r[0].text) 228 self.assertEquals('Dag', r[1].text) 229
230 - def test_xpath_extensions_nodes_append2(self):
231 def f(evaluator, nodes): 232 r = etree.Element('results') 233 b = etree.SubElement(r, 'result') 234 b.text = 'Hoi' 235 b = etree.SubElement(r, 'result') 236 b.text = 'Dag' 237 r.append(nodes[0]) 238 return r
239 240 x = self.parse('<result>Honk</result>') 241 e = etree.XPathEvaluator(x, None, [{(None, 'foo'): f}]) 242 r = e.evaluate("foo(/*)/result") 243 self.assertEquals(3, len(r)) 244 self.assertEquals('Hoi', r[0].text) 245 self.assertEquals('Dag', r[1].text) 246 self.assertEquals('Honk', r[2].text) 247
248 - def test_xpath_variables(self):
249 x = self.parse('<a attr="true"/>') 250 e = etree.XPathEvaluator(x) 251 252 expr = "/a[@attr=$aval]" 253 r = e.evaluate(expr, aval=1) 254 self.assertEquals(0, len(r)) 255 256 r = e.evaluate(expr, aval="true") 257 self.assertEquals(1, len(r)) 258 self.assertEquals("true", r[0].get('attr')) 259 260 r = e.evaluate(expr, aval=True) 261 self.assertEquals(1, len(r)) 262 self.assertEquals("true", r[0].get('attr'))
263
264 - def test_xpath_variables_nodeset(self):
265 x = self.parse('<a attr="true"/>') 266 e = etree.XPathEvaluator(x) 267 268 element = etree.Element("test-el") 269 etree.SubElement(element, "test-sub") 270 expr = "$value" 271 r = e.evaluate(expr, value=element) 272 self.assertEquals(1, len(r)) 273 self.assertEquals(element.tag, r[0].tag) 274 self.assertEquals(element[0].tag, r[0][0].tag)
275
276 - def test_xpath_extensions_mix(self):
277 x = self.parse('<a attr="true"><test/></a>') 278 279 class LocalException(Exception): 280 pass
281 282 def foo(evaluator, a, varval): 283 etree.Element("DUMMY") 284 if varval == 0: 285 raise LocalException 286 elif varval == 1: 287 return () 288 elif varval == 2: 289 return None 290 elif varval == 3: 291 return a[0][0] 292 a = a[0] 293 if a.get("attr") == str(varval): 294 return a 295 else: 296 return etree.Element("NODE") 297 298 extension = {(None, 'foo'): foo} 299 e = etree.XPathEvaluator(x, extensions=[extension]) 300 del x 301 302 self.assertRaises(LocalException, e.evaluate, "foo(., 0)") 303 self.assertRaises(LocalException, e.evaluate, "foo(., $value)", value=0) 304 305 r = e.evaluate("foo(., $value)", value=1) 306 self.assertEqual(len(r), 0) 307 308 r = e.evaluate("foo(., 1)") 309 self.assertEqual(len(r), 0) 310 311 r = e.evaluate("foo(., $value)", value=2) 312 self.assertEqual(len(r), 0) 313 314 r = e.evaluate("foo(., $value)", value=3) 315 self.assertEqual(len(r), 1) 316 self.assertEqual(r[0].tag, "test") 317 318 r = e.evaluate("foo(., $value)", value="false") 319 self.assertEqual(len(r), 1) 320 self.assertEqual(r[0].tag, "NODE") 321 322 r = e.evaluate("foo(., 'false')") 323 self.assertEqual(len(r), 1) 324 self.assertEqual(r[0].tag, "NODE") 325 326 r = e.evaluate("foo(., 'true')") 327 self.assertEqual(len(r), 1) 328 self.assertEqual(r[0].tag, "a") 329 self.assertEqual(r[0][0].tag, "test") 330 331 r = e.evaluate("foo(., $value)", value="true") 332 self.assertEqual(len(r), 1) 333 self.assertEqual(r[0].tag, "a") 334 335 self.assertRaises(LocalException, e.evaluate, "foo(., 0)") 336 self.assertRaises(LocalException, e.evaluate, "foo(., $value)", value=0) 337 338
339 -class ETreeXPathClassTestCase(HelperTestCase):
340 "Tests for the XPath class"
341 - def test_xpath_compile_doc(self):
342 x = self.parse('<a attr="true"/>') 343 344 expr = etree.XPath("/a[@attr != 'true']") 345 r = expr.evaluate(x) 346 self.assertEquals(0, len(r)) 347 348 expr = etree.XPath("/a[@attr = 'true']") 349 r = expr.evaluate(x) 350 self.assertEquals(1, len(r)) 351 352 expr = etree.XPath( expr.path ) 353 r = expr.evaluate(x) 354 self.assertEquals(1, len(r))
355
357 x = self.parse('<a><b/><c/></a>') 358 root = x.getroot() 359 360 expr = etree.XPath("./b") 361 r = expr.evaluate(root) 362 self.assertEquals(1, len(r)) 363 self.assertEquals('b', r[0].tag) 364 365 expr = etree.XPath("./*") 366 r = expr.evaluate(root) 367 self.assertEquals(2, len(r))
368
369 - def test_xpath_compile_vars(self):
370 x = self.parse('<a attr="true"/>') 371 372 expr = etree.XPath("/a[@attr=$aval]") 373 r = expr.evaluate(x, aval=False) 374 self.assertEquals(0, len(r)) 375 376 r = expr.evaluate(x, aval=True) 377 self.assertEquals(1, len(r))
378
379 - def test_xpath_compile_error(self):
380 self.assertRaises(SyntaxError, etree.XPath, '\\fad')
381
383 self.assertRaises(ValueError, etree.XPath('*'), etree.ElementTree())
384
385 -class ETreeETXPathClassTestCase(HelperTestCase):
386 "Tests for the ETXPath class"
387 - def test_xpath_compile_ns(self):
388 x = self.parse('<a><b xmlns="nsa"/><b xmlns="nsb"/></a>') 389 390 expr = etree.ETXPath("/a/{nsa}b") 391 r = expr.evaluate(x) 392 self.assertEquals(1, len(r)) 393 self.assertEquals('{nsa}b', r[0].tag) 394 395 expr = etree.ETXPath("/a/{nsb}b") 396 r = expr.evaluate(x) 397 self.assertEquals(1, len(r)) 398 self.assertEquals('{nsb}b', r[0].tag)
399
401 x = self.parse(u'<a><b xmlns="nsa\uf8d2"/><b xmlns="nsb\uf8d1"/></a>') 402 403 expr = etree.ETXPath(u"/a/{nsa\uf8d2}b") 404 r = expr.evaluate(x) 405 self.assertEquals(1, len(r)) 406 self.assertEquals(u'{nsa\uf8d2}b', r[0].tag) 407 408 expr = etree.ETXPath(u"/a/{nsb\uf8d1}b") 409 r = expr.evaluate(x) 410 self.assertEquals(1, len(r)) 411 self.assertEquals(u'{nsb\uf8d1}b', r[0].tag)
412 413 SAMPLE_XML = etree.parse(StringIO(""" 414 <body> 415 <tag>text</tag> 416 <section> 417 <tag>subtext</tag> 418 </section> 419 <tag /> 420 <tag /> 421 </body> 422 """)) 423
424 -def tag(elem):
425 return elem.tag
426
427 -def stringTest(ctxt, s1):
428 return "Hello "+s1
429
430 -def floatTest(ctxt, f1):
431 return f1+4
432
433 -def booleanTest(ctxt, b1):
434 return not b1
435
436 -def setTest(ctxt, st1):
437 return st1[0]
438
439 -def setTest2(ctxt, st1):
440 return st1[0:2]
441
442 -def argsTest1(ctxt, s, f, b, st):
443 return ", ".join(map(str, (s, f, b, map(tag, st))))
444
445 -def argsTest2(ctxt, st1, st2):
446 st1.extend(st2) 447 return st1
448
449 -def resultTypesTest(ctxt):
450 return ["x","y"]
451
452 -def resultTypesTest2(ctxt):
453 return resultTypesTest
454 455 uri = "http://www.example.com/" 456 457 extension = {(None, 'stringTest'): stringTest, 458 (None, 'floatTest'): floatTest, 459 (None, 'booleanTest'): booleanTest, 460 (None, 'setTest'): setTest, 461 (None, 'setTest2'): setTest2, 462 (None, 'argsTest1'): argsTest1, 463 (None, 'argsTest2'): argsTest2, 464 (None, 'resultTypesTest'): resultTypesTest, 465 (None, 'resultTypesTest2'): resultTypesTest2,} 466
467 -def xpath():
468 """ 469 Test xpath extension functions. 470 471 >>> root = SAMPLE_XML 472 >>> e = etree.XPathEvaluator(root, None, [extension]) 473 >>> e.evaluate("stringTest('you')") 474 'Hello you' 475 >>> e.evaluate(u"stringTest('\xe9lan')") 476 u'Hello \\xe9lan' 477 >>> e.evaluate("stringTest('you','there')") 478 Traceback (most recent call last): 479 ... 480 TypeError: stringTest() takes exactly 2 arguments (3 given) 481 >>> e.evaluate("floatTest(2)") 482 6.0 483 >>> e.evaluate("booleanTest(true())") 484 False 485 >>> map(tag, e.evaluate("setTest(/body/tag)")) 486 ['tag'] 487 >>> map(tag, e.evaluate("setTest2(/body/*)")) 488 ['tag', 'section'] 489 >>> e.evaluate("argsTest1('a',1.5,true(),/body/tag)") 490 "a, 1.5, True, ['tag', 'tag', 'tag']" 491 >>> map(tag, e.evaluate("argsTest2(/body/tag, /body/section)")) 492 ['tag', 'section', 'tag', 'tag'] 493 >>> e.evaluate("resultTypesTest()") 494 Traceback (most recent call last): 495 ... 496 XPathResultError: This is not a node: x 497 >>> try: 498 ... e.evaluate("resultTypesTest2()") 499 ... except etree.XPathResultError: 500 ... print "Got error" 501 Got error 502 """
503
504 -def test_suite():
505 suite = unittest.TestSuite() 506 suite.addTests([unittest.makeSuite(ETreeXPathTestCase)]) 507 suite.addTests([unittest.makeSuite(ETreeXPathClassTestCase)]) 508 suite.addTests([unittest.makeSuite(ETreeETXPathClassTestCase)]) 509 suite.addTests([doctest.DocTestSuite()]) 510 suite.addTests( 511 [doctest.DocFileSuite('../../../doc/xpathxslt.txt')]) 512 return suite
513 514 if __name__ == '__main__': 515 unittest.main() 516