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, sys, os.path
      8
      9  this_dir = os.path.dirname(__file__)
     10  if this_dir not in sys.path:
     11      sys.path.insert(0, this_dir) # needed for Py3
     12
     13  from common_imports import etree, HelperTestCase, _bytes, BytesIO
     14  from common_imports import doctest, make_doctest
     15
     16 -class ETreeXPathTestCase(HelperTestCase):
     17      """XPath tests etree"""
     18
     19 -    def test_xpath_boolean(self):
     20          tree = self.parse('<a><b></b><b></b></a>')
     21          self.assertTrue(tree.xpath('boolean(/a/b)'))
     22          self.assertTrue(not tree.xpath('boolean(/a/c)'))
     23
     24 -    def test_xpath_number(self):
     25          tree = self.parse('<a>1</a>')
     26          self.assertEqual(1.,
     27                            tree.xpath('number(/a)'))
     28          tree = self.parse('<a>A</a>')
     29          actual = str(tree.xpath('number(/a)'))
     30          expected = ['nan', '1.#qnan', 'nanq']
     31          if not actual.lower() in expected:
     32              self.fail('Expected a NAN value, got %s' % actual)
     33
     34 -    def test_xpath_string(self):
     35          tree = self.parse('<a>Foo</a>')
     36          self.assertEqual('Foo',
     37                            tree.xpath('string(/a/text())'))
     38
     39 -    def test_xpath_document_root(self):
     40          tree = self.parse('<a><b/></a>')
     41          self.assertEqual([],
     42                            tree.xpath('/'))
     43
     44 -    def test_xpath_namespace(self):
     45          tree = self.parse('<a xmlns="test" xmlns:p="myURI"/>')
     46          self.assertTrue((None, "test") in tree.xpath('namespace::*'))
     47          self.assertTrue(('p', 'myURI') in tree.xpath('namespace::*'))
     48
     49 -    def test_xpath_namespace_empty(self):
     50          tree = self.parse('<a/>')
     51          self.assertEqual([('xml', 'http://www.w3.org/XML/1998/namespace')],
     52                            tree.xpath('namespace::*'))
     53
     54 -    def test_xpath_list_elements(self):
     55          tree = self.parse('<a><b>Foo</b><b>Bar</b></a>')
     56          root = tree.getroot()
     57          self.assertEqual([root[0], root[1]],
     58                            tree.xpath('/a/b'))
     59
     60 -    def test_xpath_list_nothing(self):
     61          tree = self.parse('<a><b/></a>')
     62          self.assertEqual([],
     63                            tree.xpath('/a/c'))
     64          # this seems to pass a different code path, also should return nothing
     65          self.assertEqual([],
     66                            tree.xpath('/a/c/text()'))
     67
     68 -    def test_xpath_list_text(self):
     69          tree = self.parse('<a><b>Foo</b><b>Bar</b></a>')
     70          root = tree.getroot()
     71          self.assertEqual(['Foo', 'Bar'],
     72                            tree.xpath('/a/b/text()'))
     73
     74 -    def test_xpath_list_text_parent(self):
     75          tree = self.parse('<a><b>FooBar</b><b>BarFoo</b></a>')
     76          root = tree.getroot()
     77          self.assertEqual(['FooBar', 'BarFoo'],
     78                            tree.xpath('/a/b/text()'))
     79          self.assertEqual([root[0], root[1]],
     80                            [r.getparent() for r in tree.xpath('/a/b/text()')])
     81
     82 -    def test_xpath_list_text_parent_no_smart_strings(self):
     83          tree = self.parse('<a><b>FooBar</b><b>BarFoo</b></a>')
     84          root = tree.getroot()
     85          self.assertEqual(['FooBar', 'BarFoo'],
     86                            tree.xpath('/a/b/text()', smart_strings=True))
     87          self.assertEqual([root[0], root[1]],
     88                            [r.getparent() for r in
     89                             tree.xpath('/a/b/text()', smart_strings=True)])
     90          self.assertEqual([None, None],
     91                            [r.attrname for r in
     92                             tree.xpath('/a/b/text()', smart_strings=True)])
     93
     94          self.assertEqual(['FooBar', 'BarFoo'],
     95                            tree.xpath('/a/b/text()', smart_strings=False))
     96          self.assertEqual([False, False],
     97                            [hasattr(r, 'getparent') for r in
     98                             tree.xpath('/a/b/text()', smart_strings=False)])
     99          self.assertEqual([None, None],
    100                            [r.attrname for r in
    101                             tree.xpath('/a/b/text()', smart_strings=True)])
    102
    103 -    def test_xpath_list_unicode_text_parent(self):
    104          xml = _bytes('<a><b>FooBar\\u0680\\u3120</b><b>BarFoo\\u0680\\u3120</b></a>').decode("unicode_escape")
    105          tree = self.parse(xml.encode('utf-8'))
    106          root = tree.getroot()
    107          self.assertEqual([_bytes('FooBar\\u0680\\u3120').decode("unicode_escape"),
    108                             _bytes('BarFoo\\u0680\\u3120').decode("unicode_escape")],
    109                            tree.xpath('/a/b/text()'))
    110          self.assertEqual([root[0], root[1]],
    111                            [r.getparent() for r in tree.xpath('/a/b/text()')])
    112
    113 -    def test_xpath_list_attribute(self):
    114          tree = self.parse('<a b="B" c="C"/>')
    115          self.assertEqual(['B'],
    116                            tree.xpath('/a/@b'))
    117
    118 -    def test_xpath_list_attribute_parent(self):
    119          tree = self.parse('<a b="BaSdFgHjKl" c="CqWeRtZuI"/>')
    120          results = tree.xpath('/a/@c')
    121          self.assertEqual(1, len(results))
    122          self.assertEqual('CqWeRtZuI', results[0])
    123          self.assertEqual(tree.getroot().tag, results[0].getparent().tag)
    124
    125 -    def test_xpath_list_attribute_parent_no_smart_strings(self):
    126          tree = self.parse('<a b="BaSdFgHjKl" c="CqWeRtZuI"/>')
    127
    128          results = tree.xpath('/a/@c', smart_strings=True)
    129          self.assertEqual(1, len(results))
    130          self.assertEqual('CqWeRtZuI', results[0])
    131          self.assertEqual('c', results[0].attrname)
    132          self.assertEqual(tree.getroot().tag, results[0].getparent().tag)
    133
    134          results = tree.xpath('/a/@c', smart_strings=False)
    135          self.assertEqual(1, len(results))
    136          self.assertEqual('CqWeRtZuI', results[0])
    137          self.assertEqual(False, hasattr(results[0], 'getparent'))
    138          self.assertEqual(False, hasattr(results[0], 'attrname'))
    139
    140 -    def test_xpath_text_from_other_document(self):
    141          xml_data = '''
    142          <table>
    143                  <item xml:id="k1"><value>v1</value></item>
    144                  <item xml:id="k2"><value>v2</value></item>
    145          </table>
    146          '''
    147
    148          def lookup(dummy, id):
    149              return etree.XML(xml_data).xpath('id(%r)' % id)
    150          functions = {(None, 'lookup') : lookup}
    151
    152          root = etree.XML('<dummy/>')
    153          values = root.xpath("lookup('k1')/value/text()",
    154                             extensions=functions)
    155          self.assertEqual(['v1'], values)
    156          self.assertEqual('value', values[0].getparent().tag)
    157
    158 -    def test_xpath_list_comment(self):
    159          tree = self.parse('<a><!-- Foo --></a>')
    160          self.assertEqual(['<!-- Foo -->'],
    161                            list(map(repr, tree.xpath('/a/node()'))))
    162
    163 -    def test_rel_xpath_boolean(self):
    164          root = etree.XML('<a><b><c/></b></a>')
    165          el = root[0]
    166          self.assertTrue(el.xpath('boolean(c)'))
    167          self.assertTrue(not el.xpath('boolean(d)'))
    168
    169 -    def test_rel_xpath_list_elements(self):
    170          tree = self.parse('<a><c><b>Foo</b><b>Bar</b></c><c><b>Hey</b></c></a>')
    171          root = tree.getroot()
    172          c = root[0]
    173          self.assertEqual([c[0], c[1]],
    174                            c.xpath('b'))
    175          self.assertEqual([c[0], c[1], root[1][0]],
    176                            c.xpath('//b'))
    177
    178 -    def test_xpath_ns(self):
    179          tree = self.parse('<a xmlns="uri:a"><b></b></a>')
    180          root = tree.getroot()
    181          self.assertEqual(
    182              [root[0]],
    183              tree.xpath('//foo:b', namespaces={'foo': 'uri:a'}))
    184          self.assertEqual(
    185              [],
    186              tree.xpath('//foo:b', namespaces={'foo': 'uri:c'}))
    187          self.assertEqual(
    188              [root[0]],
    189              root.xpath('//baz:b', namespaces={'baz': 'uri:a'}))
    190
    191 -    def test_xpath_ns_none(self):
    192          tree = self.parse('<a xmlns="uri:a"><b></b></a>')
    193          root = tree.getroot()
    194          self.assertRaises(
    195              TypeError,
    196              root.xpath, '//b', namespaces={None: 'uri:a'})
    197
    198 -    def test_xpath_ns_empty(self):
    199          tree = self.parse('<a xmlns="uri:a"><b></b></a>')
    200          root = tree.getroot()
    201          self.assertRaises(
    202              TypeError,
    203              root.xpath, '//b', namespaces={'': 'uri:a'})
    204
    205 -    def test_xpath_error(self):
    206          tree = self.parse('<a/>')
    207          self.assertRaises(etree.XPathEvalError, tree.xpath, '\\fad')
    208
    209 -    def test_xpath_class_error(self):
    210          self.assertRaises(SyntaxError, etree.XPath, '\\fad')
    211          self.assertRaises(etree.XPathSyntaxError, etree.XPath, '\\fad')
    212
    213 -    def test_xpath_prefix_error(self):
    214          tree = self.parse('<a/>')
    215          self.assertRaises(etree.XPathEvalError, tree.xpath, '/fa:d')
    216
    217 -    def test_xpath_class_prefix_error(self):
    218          tree = self.parse('<a/>')
    219          xpath = etree.XPath("/fa:d")
    220          self.assertRaises(etree.XPathEvalError, xpath, tree)
    221
    222 -    def test_elementtree_getpath(self):
    223          a  = etree.Element("a")
    224          b  = etree.SubElement(a, "b")
    225          c  = etree.SubElement(a, "c")
    226          d1 = etree.SubElement(c, "d")
    227          d2 = etree.SubElement(c, "d")
    228
    229          tree = etree.ElementTree(a)
    230          self.assertEqual('/a/c/d',
    231                           tree.getpath(d2)[:6])
    232          self.assertEqual([d2],
    233                           tree.xpath(tree.getpath(d2)))
    234
    235 -    def test_elementtree_getpath_partial(self):
    236          a  = etree.Element("a")
    237          b  = etree.SubElement(a, "b")
    238          c  = etree.SubElement(a, "c")
    239          d1 = etree.SubElement(c, "d")
    240          d2 = etree.SubElement(c, "d")
    241
    242          tree = etree.ElementTree(c)
    243          self.assertEqual('/c/d',
    244                           tree.getpath(d2)[:4])
    245          self.assertEqual([d2],
    246                           tree.xpath(tree.getpath(d2)))
    247
    248 -    def test_xpath_evaluator(self):
    249          tree = self.parse('<a><b><c></c></b></a>')
    250          e = etree.XPathEvaluator(tree)
    251          root = tree.getroot()
    252          self.assertEqual(
    253              [root],
    254              e('//a'))
    255
    256 -    def test_xpath_evaluator_tree(self):
    257          tree = self.parse('<a><b><c></c></b></a>')
    258          child_tree = etree.ElementTree(tree.getroot()[0])
    259          e = etree.XPathEvaluator(child_tree)
    260          self.assertEqual(
    261              [],
    262              e('a'))
    263          root = child_tree.getroot()
    264          self.assertEqual(
    265              [root[0]],
    266              e('c'))
    267
    268 -    def test_xpath_evaluator_tree_absolute(self):
    269          tree = self.parse('<a><b><c></c></b></a>')
    270          child_tree = etree.ElementTree(tree.getroot()[0])
    271          e = etree.XPathEvaluator(child_tree)
    272          self.assertEqual(
    273              [],
    274              e('/a'))
    275          root = child_tree.getroot()
    276          self.assertEqual(
    277              [root],
    278              e('/b'))
    279          self.assertEqual(
    280              [],
    281              e('/c'))
    282
    283 -    def test_xpath_evaluator_element(self):
    284          tree = self.parse('<a><b><c></c></b></a>')
    285          root = tree.getroot()
    286          e = etree.XPathEvaluator(root[0])
    287          self.assertEqual(
    288              [root[0][0]],
    289              e('c'))
    290
    291 -    def test_xpath_extensions(self):
    292          def foo(evaluator, a):
    293              return 'hello %s' % a
    294          extension = {(None, 'foo'): foo}
    295          tree = self.parse('<a><b></b></a>')
    296          e = etree.XPathEvaluator(tree, extensions=[extension])
    297          self.assertEqual(
    298              "hello you", e("foo('you')"))
    299
    300 -    def test_xpath_extensions_wrong_args(self):
    301          def foo(evaluator, a, b):
    302              return "hello %s and %s" % (a, b)
    303          extension = {(None, 'foo'): foo}
    304          tree = self.parse('<a><b></b></a>')
    305          e = etree.XPathEvaluator(tree, extensions=[extension])
    306          self.assertRaises(TypeError, e, "foo('you')")
    307
    308 -    def test_xpath_extensions_error(self):
    309          def foo(evaluator, a):
    310              return 1/0
    311          extension = {(None, 'foo'): foo}
    312          tree = self.parse('<a/>')
    313          e = etree.XPathEvaluator(tree, extensions=[extension])
    314          self.assertRaises(ZeroDivisionError, e, "foo('test')")
    315
    316 -    def test_xpath_extensions_nodes(self):
    317          def f(evaluator, arg):
    318              r = etree.Element('results')
    319              b = etree.SubElement(r, 'result')
    320              b.text = 'Hoi'
    321              b = etree.SubElement(r, 'result')
    322              b.text = 'Dag'
    323              return r
    324
    325          x = self.parse('<a/>')
    326          e = etree.XPathEvaluator(x, extensions=[{(None, 'foo'): f}])
    327          r = e("foo('World')/result")
    328          self.assertEqual(2, len(r))
    329          self.assertEqual('Hoi', r[0].text)
    330          self.assertEqual('Dag', r[1].text)
    331
    332 -    def test_xpath_extensions_nodes_append(self):
    333          def f(evaluator, nodes):
    334              r = etree.SubElement(nodes[0], 'results')
    335              b = etree.SubElement(r, 'result')
    336              b.text = 'Hoi'
    337              b = etree.SubElement(r, 'result')
    338              b.text = 'Dag'
    339              return r
    340
    341          x = self.parse('<a/>')
    342          e = etree.XPathEvaluator(x, extensions=[{(None, 'foo'): f}])
    343          r = e("foo(/*)/result")
    344          self.assertEqual(2, len(r))
    345          self.assertEqual('Hoi', r[0].text)
    346          self.assertEqual('Dag', r[1].text)
    347
    348 -    def test_xpath_extensions_nodes_append2(self):
    349          def f(evaluator, nodes):
    350              r = etree.Element('results')
    351              b = etree.SubElement(r, 'result')
    352              b.text = 'Hoi'
    353              b = etree.SubElement(r, 'result')
    354              b.text = 'Dag'
    355              r.append(nodes[0])
    356              return r
    357
    358          x = self.parse('<result>Honk</result>')
    359          e = etree.XPathEvaluator(x, extensions=[{(None, 'foo'): f}])
    360          r = e("foo(/*)/result")
    361          self.assertEqual(3, len(r))
    362          self.assertEqual('Hoi',  r[0].text)
    363          self.assertEqual('Dag',  r[1].text)
    364          self.assertEqual('Honk', r[2].text)
    365
    366 -    def test_xpath_context_node(self):
    367          tree = self.parse('<root><a/><b><c/></b></root>')
    368
    369          check_call = []
    370          def check_context(ctxt, nodes):
    371              self.assertEqual(len(nodes), 1)
    372              check_call.append(nodes[0].tag)
    373              self.assertEqual(ctxt.context_node, nodes[0])
    374              return True
    375
    376          find = etree.XPath("//*[p:foo(.)]",
    377                             namespaces={'p' : 'ns'},
    378                             extensions=[{('ns', 'foo') : check_context}])
    379          find(tree)
    380
    381          check_call.sort()
    382          self.assertEqual(check_call, ["a", "b", "c", "root"])
    383
    384 -    def test_xpath_eval_context_propagation(self):
    385          tree = self.parse('<root><a/><b><c/></b></root>')
    386
    387          check_call = {}
    388          def check_context(ctxt, nodes):
    389              self.assertEqual(len(nodes), 1)
    390              tag = nodes[0].tag
    391              # empty during the "b" call, a "b" during the "c" call
    392              check_call[tag] = ctxt.eval_context.get("b")
    393              ctxt.eval_context[tag] = tag
    394              return True
    395
    396          find = etree.XPath("//b[p:foo(.)]/c[p:foo(.)]",
    397                             namespaces={'p' : 'ns'},
    398                             extensions=[{('ns', 'foo') : check_context}])
    399          result = find(tree)
    400
    401          self.assertEqual(result, [tree.getroot()[1][0]])
    402          self.assertEqual(check_call, {'b':None, 'c':'b'})
    403
    404 -    def test_xpath_eval_context_clear(self):
    405          tree = self.parse('<root><a/><b><c/></b></root>')
    406
    407          check_call = {}
    408          def check_context(ctxt):
    409              check_call["done"] = True
    410              # context must be empty for each new evaluation
    411              self.assertEqual(len(ctxt.eval_context), 0)
    412              ctxt.eval_context["test"] = True
    413              return True
    414
    415          find = etree.XPath("//b[p:foo()]",
    416                             namespaces={'p' : 'ns'},
    417                             extensions=[{('ns', 'foo') : check_context}])
    418          result = find(tree)
    419
    420          self.assertEqual(result, [tree.getroot()[1]])
    421          self.assertEqual(check_call["done"], True)
    422
    423          check_call.clear()
    424          find = etree.XPath("//b[p:foo()]",
    425                             namespaces={'p' : 'ns'},
    426                             extensions=[{('ns', 'foo') : check_context}])
    427          result = find(tree)
    428
    429          self.assertEqual(result, [tree.getroot()[1]])
    430          self.assertEqual(check_call["done"], True)
    431
    432 -    def test_xpath_variables(self):
    433          x = self.parse('<a attr="true"/>')
    434          e = etree.XPathEvaluator(x)
    435
    436          expr = "/a[@attr=$aval]"
    437          r = e(expr, aval=1)
    438          self.assertEqual(0, len(r))
    439
    440          r = e(expr, aval="true")
    441          self.assertEqual(1, len(r))
    442          self.assertEqual("true", r[0].get('attr'))
    443
    444          r = e(expr, aval=True)
    445          self.assertEqual(1, len(r))
    446          self.assertEqual("true", r[0].get('attr'))
    447
    448 -    def test_xpath_variables_nodeset(self):
    449          x = self.parse('<a attr="true"/>')
    450          e = etree.XPathEvaluator(x)
    451
    452          element = etree.Element("test-el")
    453          etree.SubElement(element, "test-sub")
    454          expr = "$value"
    455          r = e(expr, value=element)
    456          self.assertEqual(1, len(r))
    457          self.assertEqual(element.tag, r[0].tag)
    458          self.assertEqual(element[0].tag, r[0][0].tag)
    459
    460 -    def test_xpath_extensions_mix(self):
    461          x = self.parse('<a attr="true"><test/></a>')
    462
    463          class LocalException(Exception):
    464              pass
    465
    466          def foo(evaluator, a, varval):
    467              etree.Element("DUMMY")
    468              if varval == 0:
    469                  raise LocalException
    470              elif varval == 1:
    471                  return ()
    472              elif varval == 2:
    473                  return None
    474              elif varval == 3:
    475                  return a[0][0]
    476              a = a[0]
    477              if a.get("attr") == str(varval):
    478                  return a
    479              else:
    480                  return etree.Element("NODE")
    481
    482          extension = {(None, 'foo'): foo}
    483          e = etree.XPathEvaluator(x, extensions=[extension])
    484          del x
    485
    486          self.assertRaises(LocalException, e, "foo(., 0)")
    487          self.assertRaises(LocalException, e, "foo(., $value)", value=0)
    488
    489          r = e("foo(., $value)", value=1)
    490          self.assertEqual(len(r), 0)
    491
    492          r = e("foo(.,  1)")
    493          self.assertEqual(len(r), 0)
    494
    495          r = e("foo(., $value)", value=2)
    496          self.assertEqual(len(r), 0)
    497
    498          r = e("foo(., $value)", value=3)
    499          self.assertEqual(len(r), 1)
    500          self.assertEqual(r[0].tag, "test")
    501
    502          r = e("foo(., $value)", value="false")
    503          self.assertEqual(len(r), 1)
    504          self.assertEqual(r[0].tag, "NODE")
    505
    506          r = e("foo(., 'false')")
    507          self.assertEqual(len(r), 1)
    508          self.assertEqual(r[0].tag, "NODE")
    509
    510          r = e("foo(., 'true')")
    511          self.assertEqual(len(r), 1)
    512          self.assertEqual(r[0].tag, "a")
    513          self.assertEqual(r[0][0].tag, "test")
    514
    515          r = e("foo(., $value)", value="true")
    516          self.assertEqual(len(r), 1)
    517          self.assertEqual(r[0].tag, "a")
    518
    519          self.assertRaises(LocalException, e, "foo(., 0)")
    520          self.assertRaises(LocalException, e, "foo(., $value)", value=0)
    521
    522
    523 -class ETreeXPathClassTestCase(HelperTestCase):
    524      "Tests for the XPath class"
    525 -    def test_xpath_compile_doc(self):
    526          x = self.parse('<a attr="true"/>')
    527
    528          expr = etree.XPath("/a[@attr != 'true']")
    529          r = expr(x)
    530          self.assertEqual(0, len(r))
    531
    532          expr = etree.XPath("/a[@attr = 'true']")
    533          r = expr(x)
    534          self.assertEqual(1, len(r))
    535
    536          expr = etree.XPath( expr.path )
    537          r = expr(x)
    538          self.assertEqual(1, len(r))
    539
    540 -    def test_xpath_compile_element(self):
    541          x = self.parse('<a><b/><c/></a>')
    542          root = x.getroot()
    543
    544          expr = etree.XPath("./b")
    545          r = expr(root)
    546          self.assertEqual(1, len(r))
    547          self.assertEqual('b', r[0].tag)
    548
    549          expr = etree.XPath("./*")
    550          r = expr(root)
    551          self.assertEqual(2, len(r))
    552
    553 -    def test_xpath_compile_vars(self):
    554          x = self.parse('<a attr="true"/>')
    555
    556          expr = etree.XPath("/a[@attr=$aval]")
    557          r = expr(x, aval=False)
    558          self.assertEqual(0, len(r))
    559
    560          r = expr(x, aval=True)
    561          self.assertEqual(1, len(r))
    562
    563 -    def test_xpath_compile_error(self):
    564          self.assertRaises(SyntaxError, etree.XPath, '\\fad')
    565
    566 -    def test_xpath_elementtree_error(self):
    567          self.assertRaises(ValueError, etree.XPath('*'), etree.ElementTree())
    568
    569
    570 -class ETreeXPathExsltTestCase(HelperTestCase):
    571      "Tests for the EXSLT support in XPath (requires libxslt 1.1.25+)"
    572
    573      NSMAP = dict(
    574          date = "http://exslt.org/dates-and-times",
    575          math = "http://exslt.org/math",
    576          set  = "http://exslt.org/sets",
    577          str  = "http://exslt.org/strings",
    578          )
    579
    580 -    def test_xpath_exslt_functions_date(self):
    581          tree = self.parse('<a><b>2009-11-12</b><b>2008-12-11</b></a>')
    582
    583          match_dates = tree.xpath('//b[date:year(string()) = 2009]',
    584                                   namespaces=self.NSMAP)
    585          self.assertTrue(match_dates, str(match_dates))
    586          self.assertEqual(len(match_dates), 1, str(match_dates))
    587          self.assertEqual(match_dates[0].text, '2009-11-12')
    588
    589 -    def test_xpath_exslt_functions_strings(self):
    590          tree = self.parse('<a><b>2009-11-12</b><b>2008-12-11</b></a>')
    591
    592          aligned_date = tree.xpath(
    593              'str:align(string(//b[1]), "%s", "center")' % ('-'*20),
    594              namespaces=self.NSMAP)
    595          self.assertTrue(aligned_date, str(aligned_date))
    596          self.assertEqual(aligned_date, '-----2009-11-12-----')
    597
    598
    599 -class ETreeETXPathClassTestCase(HelperTestCase):
    600      "Tests for the ETXPath class"
    601 -    def test_xpath_compile_ns(self):
    602          x = self.parse('<a><b xmlns="nsa"/><b xmlns="nsb"/></a>')
    603
    604          expr = etree.ETXPath("/a/{nsa}b")
    605          r = expr(x)
    606          self.assertEqual(1, len(r))
    607          self.assertEqual('{nsa}b', r[0].tag)
    608
    609          expr = etree.ETXPath("/a/{nsb}b")
    610          r = expr(x)
    611          self.assertEqual(1, len(r))
    612          self.assertEqual('{nsb}b', r[0].tag)
    613
    614      # disabled this test as non-ASCII characters in namespace URIs are
    615      # not acceptable
    616 -    def _test_xpath_compile_unicode(self):
    617          x = self.parse(_bytes('<a><b xmlns="http://nsa/\\uf8d2"/><b xmlns="http://nsb/\\uf8d1"/></a>'
    618                                ).decode("unicode_escape"))
    619
    620          expr = etree.ETXPath(_bytes("/a/{http://nsa/\\uf8d2}b").decode("unicode_escape"))
    621          r = expr(x)
    622          self.assertEqual(1, len(r))
    623          self.assertEqual(_bytes('{http://nsa/\\uf8d2}b').decode("unicode_escape"), r[0].tag)
    624
    625          expr = etree.ETXPath(_bytes("/a/{http://nsb/\\uf8d1}b").decode("unicode_escape"))
    626          r = expr(x)
    627          self.assertEqual(1, len(r))
    628          self.assertEqual(_bytes('{http://nsb/\\uf8d1}b').decode("unicode_escape"), r[0].tag)
    629
    630  SAMPLE_XML = etree.parse(BytesIO("""
    631  <body>
    632    <tag>text</tag>
    633    <section>
    634      <tag>subtext</tag>
    635    </section>
    636    <tag />
    637    <tag />
    638  </body>
    639  """))
    640
    641 -def tag(elem):
    642      return elem.tag
    643
    644 -def tag_or_value(elem):
    645      return getattr(elem, 'tag', elem)
    646
    647 -def stringTest(ctxt, s1):
    648      return "Hello "+s1
    649
    650 -def stringListTest(ctxt, s1):
    651      return ["Hello "] + list(s1) +  ["!"]
    652
    653 -def floatTest(ctxt, f1):
    654      return f1+4
    655
    656 -def booleanTest(ctxt, b1):
    657      return not b1
    658
    659 -def setTest(ctxt, st1):
    660      return st1[0]
    661
    662 -def setTest2(ctxt, st1):
    663      return st1[0:2]
    664
    665 -def argsTest1(ctxt, s, f, b, st):
    666      return ", ".join(map(str, (s, f, b, list(map(tag, st)))))
    667
    668 -def argsTest2(ctxt, st1, st2):
    669      st1.extend(st2)
    670      return st1
    671
    672 -def resultTypesTest(ctxt):
    673      return [None,None]
    674
    675 -def resultTypesTest2(ctxt):
    676      return resultTypesTest
    677
    678  uri = "http://www.example.com/"
    679
    680  extension = {(None, 'stringTest'): stringTest,
    681               (None, 'stringListTest'): stringListTest,
    682               (None, 'floatTest'): floatTest,
    683               (None, 'booleanTest'): booleanTest,
    684               (None, 'setTest'): setTest,
    685               (None, 'setTest2'): setTest2,
    686               (None, 'argsTest1'): argsTest1,
    687               (None, 'argsTest2'): argsTest2,
    688               (None, 'resultTypesTest'): resultTypesTest,
    689               (None, 'resultTypesTest2'): resultTypesTest2,}
    690
    691 -def xpath():
    692      """
    693      Test xpath extension functions.
    694
    695      >>> root = SAMPLE_XML
    696      >>> e = etree.XPathEvaluator(root, extensions=[extension])
    697      >>> e("stringTest('you')")
    698      'Hello you'
    699      >>> e(_bytes("stringTest('\\\\xe9lan')").decode("unicode_escape"))
    700      u'Hello \\xe9lan'
    701      >>> e("stringTest('you','there')")   #doctest: +ELLIPSIS
    702      Traceback (most recent call last):
    703      ...
    704      TypeError: stringTest() takes... 2 ...arguments ...
    705      >>> e("floatTest(2)")
    706      6.0
    707      >>> e("booleanTest(true())")
    708      False
    709      >>> list(map(tag, e("setTest(/body/tag)")))
    710      ['tag']
    711      >>> list(map(tag, e("setTest2(/body/*)")))
    712      ['tag', 'section']
    713      >>> list(map(tag_or_value, e("stringListTest(/body/tag)")))
    714      ['Hello ', 'tag', 'tag', 'tag', '!']
    715      >>> e("argsTest1('a',1.5,true(),/body/tag)")
    716      "a, 1.5, True, ['tag', 'tag', 'tag']"
    717      >>> list(map(tag, e("argsTest2(/body/tag, /body/section)")))
    718      ['tag', 'section', 'tag', 'tag']
    719      >>> e("resultTypesTest()")
    720      Traceback (most recent call last):
    721      ...
    722      XPathResultError: This is not a supported node-set result: None
    723      >>> try:
    724      ...     e("resultTypesTest2()")
    725      ... except etree.XPathResultError:
    726      ...     print("Got error")
    727      Got error
    728      """
    729
    730  if sys.version_info[0] >= 3:
    731      xpath.__doc__ = xpath.__doc__.replace(" u'", " '")
    732      xpath.__doc__ = xpath.__doc__.replace(" XPathResultError",
    733                                            " lxml.etree.XPathResultError")
    734      xpath.__doc__ = xpath.__doc__.replace(" exactly 2 arguments",
    735                                            " exactly 2 positional arguments")
    736
    737 -def test_suite():
    738      suite = unittest.TestSuite()
    739      suite.addTests([unittest.makeSuite(ETreeXPathTestCase)])
    740      suite.addTests([unittest.makeSuite(ETreeXPathClassTestCase)])
    741      if etree.LIBXSLT_COMPILED_VERSION >= (1,1,25):
    742          suite.addTests([unittest.makeSuite(ETreeXPathExsltTestCase)])
    743      suite.addTests([unittest.makeSuite(ETreeETXPathClassTestCase)])
    744      suite.addTests([doctest.DocTestSuite()])
    745      suite.addTests(
    746          [make_doctest('../../../doc/xpathxslt.txt')])
    747      return suite
    748
    749  if __name__ == '__main__':
    750      print('to test use test.py %s' % __file__)
    751