1
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
13 """XPath tests etree"""
14
19
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
31 tree = self.parse('<a>Foo</a>')
32 self.assertEquals('Foo',
33 tree.xpath('string(/a/text())'))
34
36 tree = self.parse('<a><b/></a>')
37 self.assertEquals([],
38 tree.xpath('/'))
39
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
55
57 tree = self.parse('<a><b/></a>')
58 self.assertEquals([],
59 tree.xpath('/a/c'))
60
61 self.assertEquals([],
62 tree.xpath('/a/c/text()'))
63
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
79
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
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
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
116 tree = self.parse('<a xmlns="uri:a"><b></b></a>')
117 root = tree.getroot()
118 self.assertRaises(
119 TypeError,
120 root.xpath, '//b', {'': 'uri:a'})
121
125
129
133
138
151
164
172
184
192
194 def foo(evaluator, a):
195 return 'hello %s' % a
196 extension = {(None, 'foo'): foo}
197 tree = self.parse('<a><b></b></a>')
198 e = etree.XPathEvaluator(tree, None, [extension])
199 self.assertEquals(
200 "hello you", e.evaluate("foo('you')"))
201
203 def foo(evaluator, a, b):
204 return "hello %s and %s" % (a, b)
205 extension = {(None, 'foo'): foo}
206 tree = self.parse('<a><b></b></a>')
207 e = etree.XPathEvaluator(tree, extensions=[extension])
208 self.assertRaises(TypeError, e.evaluate, "foo('you')")
209
211 def foo(evaluator, a):
212 return 1/0
213 extension = {(None, 'foo'): foo}
214 tree = self.parse('<a/>')
215 e = etree.XPathEvaluator(tree, None, [extension])
216 self.assertRaises(ZeroDivisionError, e.evaluate, "foo('test')")
217
226
227 x = self.parse('<a/>')
228 e = etree.XPathEvaluator(x, None, [{(None, 'foo'): f}])
229 r = e.evaluate("foo('World')/result")
230 self.assertEquals(2, len(r))
231 self.assertEquals('Hoi', r[0].text)
232 self.assertEquals('Dag', r[1].text)
233
242
243 x = self.parse('<a/>')
244 e = etree.XPathEvaluator(x, None, [{(None, 'foo'): f}])
245 r = e.evaluate("foo(/*)/result")
246 self.assertEquals(2, len(r))
247 self.assertEquals('Hoi', r[0].text)
248 self.assertEquals('Dag', r[1].text)
249
259
260 x = self.parse('<result>Honk</result>')
261 e = etree.XPathEvaluator(x, None, [{(None, 'foo'): f}])
262 r = e.evaluate("foo(/*)/result")
263 self.assertEquals(3, len(r))
264 self.assertEquals('Hoi', r[0].text)
265 self.assertEquals('Dag', r[1].text)
266 self.assertEquals('Honk', r[2].text)
267
269 tree = self.parse('<root><a/><b><c/></b></root>')
270
271 check_call = []
272 def check_context(ctxt, nodes):
273 self.assertEquals(len(nodes), 1)
274 check_call.append(nodes[0].tag)
275 self.assertEquals(ctxt.context_node, nodes[0])
276 return True
277
278 find = etree.XPath("//*[p:foo(.)]",
279 namespaces={'p' : 'ns'},
280 extensions=[{('ns', 'foo') : check_context}])
281 find(tree)
282
283 check_call.sort()
284 self.assertEquals(check_call, ["a", "b", "c", "root"])
285
287 tree = self.parse('<root><a/><b><c/></b></root>')
288
289 check_call = {}
290 def check_context(ctxt, nodes):
291 self.assertEquals(len(nodes), 1)
292 tag = nodes[0].tag
293
294 check_call[tag] = ctxt.eval_context.get("b")
295 ctxt.eval_context[tag] = tag
296 return True
297
298 find = etree.XPath("//b[p:foo(.)]/c[p:foo(.)]",
299 namespaces={'p' : 'ns'},
300 extensions=[{('ns', 'foo') : check_context}])
301 result = find(tree)
302
303 self.assertEquals(result, [tree.getroot()[1][0]])
304 self.assertEquals(check_call, {'b':None, 'c':'b'})
305
307 tree = self.parse('<root><a/><b><c/></b></root>')
308
309 check_call = {}
310 def check_context(ctxt):
311 check_call["done"] = True
312
313 self.assertEquals(len(ctxt.eval_context), 0)
314 ctxt.eval_context["test"] = True
315 return True
316
317 find = etree.XPath("//b[p:foo()]",
318 namespaces={'p' : 'ns'},
319 extensions=[{('ns', 'foo') : check_context}])
320 result = find(tree)
321
322 self.assertEquals(result, [tree.getroot()[1]])
323 self.assertEquals(check_call["done"], True)
324
325 check_call.clear()
326 find = etree.XPath("//b[p:foo()]",
327 namespaces={'p' : 'ns'},
328 extensions=[{('ns', 'foo') : check_context}])
329 result = find(tree)
330
331 self.assertEquals(result, [tree.getroot()[1]])
332 self.assertEquals(check_call["done"], True)
333
335 x = self.parse('<a attr="true"/>')
336 e = etree.XPathEvaluator(x)
337
338 expr = "/a[@attr=$aval]"
339 r = e.evaluate(expr, aval=1)
340 self.assertEquals(0, len(r))
341
342 r = e.evaluate(expr, aval="true")
343 self.assertEquals(1, len(r))
344 self.assertEquals("true", r[0].get('attr'))
345
346 r = e.evaluate(expr, aval=True)
347 self.assertEquals(1, len(r))
348 self.assertEquals("true", r[0].get('attr'))
349
361
363 x = self.parse('<a attr="true"><test/></a>')
364
365 class LocalException(Exception):
366 pass
367
368 def foo(evaluator, a, varval):
369 etree.Element("DUMMY")
370 if varval == 0:
371 raise LocalException
372 elif varval == 1:
373 return ()
374 elif varval == 2:
375 return None
376 elif varval == 3:
377 return a[0][0]
378 a = a[0]
379 if a.get("attr") == str(varval):
380 return a
381 else:
382 return etree.Element("NODE")
383
384 extension = {(None, 'foo'): foo}
385 e = etree.XPathEvaluator(x, extensions=[extension])
386 del x
387
388 self.assertRaises(LocalException, e.evaluate, "foo(., 0)")
389 self.assertRaises(LocalException, e.evaluate, "foo(., $value)", value=0)
390
391 r = e.evaluate("foo(., $value)", value=1)
392 self.assertEqual(len(r), 0)
393
394 r = e.evaluate("foo(., 1)")
395 self.assertEqual(len(r), 0)
396
397 r = e.evaluate("foo(., $value)", value=2)
398 self.assertEqual(len(r), 0)
399
400 r = e.evaluate("foo(., $value)", value=3)
401 self.assertEqual(len(r), 1)
402 self.assertEqual(r[0].tag, "test")
403
404 r = e.evaluate("foo(., $value)", value="false")
405 self.assertEqual(len(r), 1)
406 self.assertEqual(r[0].tag, "NODE")
407
408 r = e.evaluate("foo(., 'false')")
409 self.assertEqual(len(r), 1)
410 self.assertEqual(r[0].tag, "NODE")
411
412 r = e.evaluate("foo(., 'true')")
413 self.assertEqual(len(r), 1)
414 self.assertEqual(r[0].tag, "a")
415 self.assertEqual(r[0][0].tag, "test")
416
417 r = e.evaluate("foo(., $value)", value="true")
418 self.assertEqual(len(r), 1)
419 self.assertEqual(r[0].tag, "a")
420
421 self.assertRaises(LocalException, e.evaluate, "foo(., 0)")
422 self.assertRaises(LocalException, e.evaluate, "foo(., $value)", value=0)
423
424
426 "Tests for the XPath class"
428 x = self.parse('<a attr="true"/>')
429
430 expr = etree.XPath("/a[@attr != 'true']")
431 r = expr.evaluate(x)
432 self.assertEquals(0, len(r))
433
434 expr = etree.XPath("/a[@attr = 'true']")
435 r = expr.evaluate(x)
436 self.assertEquals(1, len(r))
437
438 expr = etree.XPath( expr.path )
439 r = expr.evaluate(x)
440 self.assertEquals(1, len(r))
441
454
456 x = self.parse('<a attr="true"/>')
457
458 expr = etree.XPath("/a[@attr=$aval]")
459 r = expr.evaluate(x, aval=False)
460 self.assertEquals(0, len(r))
461
462 r = expr.evaluate(x, aval=True)
463 self.assertEquals(1, len(r))
464
466 self.assertRaises(SyntaxError, etree.XPath, '\\fad')
467
470
472 "Tests for the ETXPath class"
474 x = self.parse('<a><b xmlns="nsa"/><b xmlns="nsb"/></a>')
475
476 expr = etree.ETXPath("/a/{nsa}b")
477 r = expr.evaluate(x)
478 self.assertEquals(1, len(r))
479 self.assertEquals('{nsa}b', r[0].tag)
480
481 expr = etree.ETXPath("/a/{nsb}b")
482 r = expr.evaluate(x)
483 self.assertEquals(1, len(r))
484 self.assertEquals('{nsb}b', r[0].tag)
485
487 x = self.parse(u'<a><b xmlns="nsa\uf8d2"/><b xmlns="nsb\uf8d1"/></a>')
488
489 expr = etree.ETXPath(u"/a/{nsa\uf8d2}b")
490 r = expr.evaluate(x)
491 self.assertEquals(1, len(r))
492 self.assertEquals(u'{nsa\uf8d2}b', r[0].tag)
493
494 expr = etree.ETXPath(u"/a/{nsb\uf8d1}b")
495 r = expr.evaluate(x)
496 self.assertEquals(1, len(r))
497 self.assertEquals(u'{nsb\uf8d1}b', r[0].tag)
498
499 SAMPLE_XML = etree.parse(StringIO("""
500 <body>
501 <tag>text</tag>
502 <section>
503 <tag>subtext</tag>
504 </section>
505 <tag />
506 <tag />
507 </body>
508 """))
509
512
515
518
521
524
527
529 return ", ".join(map(str, (s, f, b, map(tag, st))))
530
532 st1.extend(st2)
533 return st1
534
537
540
541 uri = "http://www.example.com/"
542
543 extension = {(None, 'stringTest'): stringTest,
544 (None, 'floatTest'): floatTest,
545 (None, 'booleanTest'): booleanTest,
546 (None, 'setTest'): setTest,
547 (None, 'setTest2'): setTest2,
548 (None, 'argsTest1'): argsTest1,
549 (None, 'argsTest2'): argsTest2,
550 (None, 'resultTypesTest'): resultTypesTest,
551 (None, 'resultTypesTest2'): resultTypesTest2,}
552
554 """
555 Test xpath extension functions.
556
557 >>> root = SAMPLE_XML
558 >>> e = etree.XPathEvaluator(root, None, [extension])
559 >>> e.evaluate("stringTest('you')")
560 'Hello you'
561 >>> e.evaluate(u"stringTest('\xe9lan')")
562 u'Hello \\xe9lan'
563 >>> e.evaluate("stringTest('you','there')")
564 Traceback (most recent call last):
565 ...
566 TypeError: stringTest() takes exactly 2 arguments (3 given)
567 >>> e.evaluate("floatTest(2)")
568 6.0
569 >>> e.evaluate("booleanTest(true())")
570 False
571 >>> map(tag, e.evaluate("setTest(/body/tag)"))
572 ['tag']
573 >>> map(tag, e.evaluate("setTest2(/body/*)"))
574 ['tag', 'section']
575 >>> e.evaluate("argsTest1('a',1.5,true(),/body/tag)")
576 "a, 1.5, True, ['tag', 'tag', 'tag']"
577 >>> map(tag, e.evaluate("argsTest2(/body/tag, /body/section)"))
578 ['tag', 'section', 'tag', 'tag']
579 >>> e.evaluate("resultTypesTest()")
580 Traceback (most recent call last):
581 ...
582 XPathResultError: This is not a node: x
583 >>> try:
584 ... e.evaluate("resultTypesTest2()")
585 ... except etree.XPathResultError:
586 ... print "Got error"
587 Got error
588 """
589
591 suite = unittest.TestSuite()
592 suite.addTests([unittest.makeSuite(ETreeXPathTestCase)])
593 suite.addTests([unittest.makeSuite(ETreeXPathClassTestCase)])
594 suite.addTests([unittest.makeSuite(ETreeETXPathClassTestCase)])
595 suite.addTests([doctest.DocTestSuite()])
596 suite.addTests(
597 [doctest.DocFileSuite('../../../doc/xpathxslt.txt')])
598 return suite
599
600 if __name__ == '__main__':
601 print 'to test use test.py %s' % __file__
602