lxml.tests.test_xpathevaluator

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