lxml.tests.test_elementpath

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

# Source Code for Module lxml.tests.test_elementpath

      1  # -*- coding: utf-8 -*-
      2
      3  """
      4  Tests for the ElementPath implementation.
      5  """
      6
      7  from __future__ import absolute_import
      8
      9  import unittest
     10  from copy import deepcopy
     11  from .common_imports import etree, HelperTestCase
     12
     13
     14 -def summarize(elem):
     15      return elem.tag
     16
     17 -def summarize_list(seq):
     18      return list(map(summarize, seq))
     19
     20 -def normalize_crlf(tree):
     21      for elem in tree.getiterator():
     22          if elem.text: elem.text = elem.text.replace("\r\n", "\n")
     23          if elem.tail: elem.tail = elem.tail.replace("\r\n", "\n")
     24
     25
     26 -class EtreeElementPathTestCase(HelperTestCase):
     27      etree = etree
     28      from lxml import _elementpath
     29
     30 -    def test_cache(self):
     31          self._elementpath._cache.clear()
     32          el = self.etree.XML(b'<a><b><c/><c/></b></a>')
     33          self.assertFalse(self._elementpath._cache)
     34
     35          self.assertTrue(el.findall('b/c'))
     36          self.assertEqual(1, len(self._elementpath._cache))
     37          self.assertTrue(el.findall('b/c'))
     38          self.assertEqual(1, len(self._elementpath._cache))
     39          self.assertFalse(el.findall('xxx'))
     40          self.assertEqual(2, len(self._elementpath._cache))
     41          self.assertFalse(el.findall('xxx'))
     42          self.assertEqual(2, len(self._elementpath._cache))
     43          self.assertTrue(el.findall('b/c'))
     44          self.assertEqual(2, len(self._elementpath._cache))
     45
     46 -    def _assert_tokens(self, tokens, path, namespaces=None):
     47          self.assertEqual(tokens, list(self._elementpath.xpath_tokenizer(path, namespaces)))
     48
     49 -    def test_tokenizer(self):
     50          assert_tokens = self._assert_tokens
     51          assert_tokens(
     52              [('/', '')],
     53              '/',
     54          )
     55          assert_tokens(
     56              [('.', ''), ('/', ''), ('', 'a'), ('/', ''), ('', 'b'), ('/', ''), ('', 'c')],
     57              './a/b/c',
     58          )
     59          assert_tokens(
     60              [('/', ''), ('', 'a'), ('/', ''), ('', 'b'), ('/', ''), ('', 'c')],
     61              '/a/b/c',
     62          )
     63          assert_tokens(
     64              [('/', ''), ('', '{nsx}a'), ('/', ''), ('', '{nsy}b'), ('/', ''), ('', 'c')],
     65              '/x:a/y:b/c',
     66              {'x': 'nsx', 'y': 'nsy'},
     67          )
     68          assert_tokens(
     69              [('/', ''), ('', '{nsx}a'), ('/', ''), ('', '{nsy}b'), ('/', ''), ('', '{nsnone}c')],
     70              '/x:a/y:b/c',
     71              {'x': 'nsx', 'y': 'nsy', None: 'nsnone'},
     72          )
     73
     74 -    def test_tokenizer_predicates(self):
     75          assert_tokens = self._assert_tokens
     76          assert_tokens(
     77              [('', 'a'), ('[', ''), ('', 'b'), (']', '')],
     78              'a[b]',
     79          )
     80          assert_tokens(
     81              [('', 'a'), ('[', ''), ('', 'b'), ('=', ''), ('"abc"', ''), (']', '')],
     82              'a[b="abc"]',
     83          )
     84          assert_tokens(
     85              [('', 'a'), ('[', ''), ('.', ''), ('', ''), ('=', ''), ('', ''), ('"abc"', ''), (']', '')],
     86              'a[. = "abc"]',
     87          )
     88
     89 -    def test_xpath_tokenizer(self):
     90          # Test the XPath tokenizer.  Copied from CPython's "test_xml_etree.py"
     91          ElementPath = self._elementpath
     92
     93          def check(p, expected, namespaces=None):
     94              self.assertEqual([op or tag
     95                                for op, tag in ElementPath.xpath_tokenizer(p, namespaces)],
     96                               expected)
     97
     98          # tests from the xml specification
     99          check("*", ['*'])
    100          check("text()", ['text', '()'])
    101          check("@name", ['@', 'name'])
    102          check("@*", ['@', '*'])
    103          check("para[1]", ['para', '[', '1', ']'])
    104          check("para[last()]", ['para', '[', 'last', '()', ']'])
    105          check("*/para", ['*', '/', 'para'])
    106          check("/doc/chapter[5]/section[2]",
    107                ['/', 'doc', '/', 'chapter', '[', '5', ']',
    108                 '/', 'section', '[', '2', ']'])
    109          check("chapter//para", ['chapter', '//', 'para'])
    110          check("//para", ['//', 'para'])
    111          check("//olist/item", ['//', 'olist', '/', 'item'])
    112          check(".", ['.'])
    113          check(".//para", ['.', '//', 'para'])
    114          check("..", ['..'])
    115          check("../@lang", ['..', '/', '@', 'lang'])
    116          check("chapter[title]", ['chapter', '[', 'title', ']'])
    117          check("employee[@secretary and @assistant]", ['employee',
    118                '[', '@', 'secretary', '', 'and', '', '@', 'assistant', ']'])
    119
    120          # additional tests
    121          check("@{ns}attr", ['@', '{ns}attr'])
    122          check("{http://spam}egg", ['{http://spam}egg'])
    123          check("./spam.egg", ['.', '/', 'spam.egg'])
    124          check(".//{http://spam}egg", ['.', '//', '{http://spam}egg'])
    125
    126          # wildcard tags
    127          check("{ns}*", ['{ns}*'])
    128          check("{}*", ['{}*'])
    129          check("{*}tag", ['{*}tag'])
    130          check("{*}*", ['{*}*'])
    131          check(".//{*}tag", ['.', '//', '{*}tag'])
    132
    133          # namespace prefix resolution
    134          check("./xsd:type", ['.', '/', '{http://www.w3.org/2001/XMLSchema}type'],
    135                {'xsd': 'http://www.w3.org/2001/XMLSchema'})
    136          check("type", ['{http://www.w3.org/2001/XMLSchema}type'],
    137                {'': 'http://www.w3.org/2001/XMLSchema'})
    138          check("@xsd:type", ['@', '{http://www.w3.org/2001/XMLSchema}type'],
    139                {'xsd': 'http://www.w3.org/2001/XMLSchema'})
    140          check("@type", ['@', 'type'],
    141                {'': 'http://www.w3.org/2001/XMLSchema'})
    142          check("@{*}type", ['@', '{*}type'],
    143                {'': 'http://www.w3.org/2001/XMLSchema'})
    144          check("@{ns}attr", ['@', '{ns}attr'],
    145                {'': 'http://www.w3.org/2001/XMLSchema',
    146                 'ns': 'http://www.w3.org/2001/XMLSchema'})
    147
    148 -    def test_find(self):
    149          """
    150          Test find methods (including xpath syntax).
    151          Originally copied from 'selftest.py'.
    152          """
    153          elem = etree.XML("""
    154          <body>
    155            <tag class='a'>text</tag>
    156            <tag class='b' />
    157            <section>
    158              <tag class='b' id='inner'>subtext</tag>
    159            </section>
    160          </body>
    161          """)
    162
    163          self.assertEqual(elem.find("tag").tag,
    164                           'tag')
    165          self.assertEqual(etree.ElementTree(elem).find("tag").tag,
    166                           'tag')
    167          self.assertEqual(elem.find("section/tag").tag,
    168                           'tag')
    169          self.assertEqual(etree.ElementTree(elem).find("section/tag").tag,
    170                           'tag')
    171
    172          self.assertEqual(elem.findtext("tag"),
    173                           'text')
    174          self.assertEqual(elem.findtext("tog"),
    175                           None)
    176          self.assertEqual(elem.findtext("tog", "default"),
    177                           'default')
    178          self.assertEqual(etree.ElementTree(elem).findtext("tag"),
    179                           'text')
    180          self.assertEqual(elem.findtext("section/tag"),
    181                           'subtext')
    182          self.assertEqual(etree.ElementTree(elem).findtext("section/tag"),
    183                           'subtext')
    184
    185          self.assertEqual(summarize_list(elem.findall("tag")),
    186                           ['tag', 'tag'])
    187          self.assertEqual(summarize_list(elem.findall("*")),
    188                           ['tag', 'tag', 'section'])
    189          self.assertEqual(summarize_list(elem.findall(".//tag")),
    190                           ['tag', 'tag', 'tag'])
    191          self.assertEqual(summarize_list(elem.findall("section/tag")),
    192                           ['tag'])
    193          self.assertEqual(summarize_list(elem.findall("section//tag")),
    194                           ['tag'])
    195
    196          self.assertEqual(summarize_list(elem.findall("section/*")),
    197                           ['tag'])
    198          self.assertEqual(summarize_list(elem.findall("section//*")),
    199                           ['tag'])
    200          self.assertEqual(summarize_list(elem.findall("section/.//*")),
    201                           ['tag'])
    202          self.assertEqual(summarize_list(elem.findall("*/*")),
    203                           ['tag'])
    204          self.assertEqual(summarize_list(elem.findall("*//*")),
    205                           ['tag'])
    206          self.assertEqual(summarize_list(elem.findall("*/tag")),
    207                           ['tag'])
    208          self.assertEqual(summarize_list(elem.findall("*/./tag")),
    209                           ['tag'])
    210          self.assertEqual(summarize_list(elem.findall("./tag")),
    211                           ['tag', 'tag'])
    212          self.assertEqual(summarize_list(elem.findall(".//tag")),
    213                           ['tag', 'tag', 'tag'])
    214          self.assertEqual(summarize_list(elem.findall("././tag")),
    215                           ['tag', 'tag'])
    216
    217          self.assertEqual(summarize_list(elem.findall(".//tag[@class]")),
    218                           ['tag', 'tag', 'tag'])
    219          self.assertEqual(summarize_list(elem.findall(".//tag[ @class]")),
    220                           ['tag', 'tag', 'tag'])
    221          self.assertEqual(summarize_list(elem.findall(".//tag[@class ]")),
    222                           ['tag', 'tag', 'tag'])
    223          self.assertEqual(summarize_list(elem.findall(".//tag[  @class  ]")),
    224                           ['tag', 'tag', 'tag'])
    225          self.assertEqual(summarize_list(elem.findall(".//tag[@class='a']")),
    226                           ['tag'])
    227          self.assertEqual(summarize_list(elem.findall('.//tag[@class="a"]')),
    228                           ['tag'])
    229          self.assertEqual(summarize_list(elem.findall(".//tag[@class='b']")),
    230                           ['tag', 'tag'])
    231          self.assertEqual(summarize_list(elem.findall('.//tag[@class="b"]')),
    232                           ['tag', 'tag'])
    233          self.assertEqual(summarize_list(elem.findall('.//tag[@class = "b"]')),
    234                           ['tag', 'tag'])
    235          self.assertEqual(summarize_list(elem.findall(".//tag[@id]")),
    236                           ['tag'])
    237          self.assertEqual(summarize_list(elem.findall(".//tag[@class][@id]")),
    238                           ['tag'])
    239          self.assertEqual(summarize_list(elem.findall(".//section[tag]")),
    240                           ['section'])
    241          self.assertEqual(summarize_list(elem.findall(".//section[element]")),
    242                           [])
    243
    244          self.assertEqual(summarize_list(elem.findall(".//section[tag='subtext']")),
    245                           ['section'])
    246          self.assertEqual(summarize_list(elem.findall(".//section[tag ='subtext']")),
    247                           ['section'])
    248          self.assertEqual(summarize_list(elem.findall(".//section[tag= 'subtext']")),
    249                           ['section'])
    250          self.assertEqual(summarize_list(elem.findall(".//section[tag = 'subtext']")),
    251                           ['section'])
    252          self.assertEqual(summarize_list(elem.findall(".//section[  tag   =   'subtext'  ]")),
    253                           ['section'])
    254          self.assertEqual(summarize_list(elem.findall(".//tag[.='subtext']")),
    255                           ['tag'])
    256          self.assertEqual(summarize_list(elem.findall(".//tag[. ='subtext']")),
    257                           ['tag'])
    258          self.assertEqual(summarize_list(elem.findall('.//tag[.= "subtext"]')),
    259                           ['tag'])
    260          self.assertEqual(summarize_list(elem.findall(".//tag[. = 'subtext']")),
    261                           ['tag'])
    262          self.assertEqual(summarize_list(elem.findall(".//tag[. = 'subtext ']")),
    263                           [])
    264          self.assertEqual(summarize_list(elem.findall(".//tag[.= ' subtext']")),
    265                           [])
    266
    267          self.assertEqual(summarize_list(elem.findall("../tag")),
    268                           [])
    269          self.assertEqual(summarize_list(elem.findall("section/../tag")),
    270                           ['tag', 'tag'])
    271          self.assertEqual(summarize_list(etree.ElementTree(elem).findall("./tag")),
    272                           ['tag', 'tag'])
    273
    274          # FIXME: ET's Path module handles this case incorrectly; this gives
    275          # a warning in 1.3, and the behaviour will be modified in 1.4.
    276          self.assertEqual(summarize_list(etree.ElementTree(elem).findall("/tag")),
    277                           ['tag', 'tag'])
    278
    279          # duplicate section => 2x tag matches
    280          elem[1] = deepcopy(elem[2])
    281          self.assertEqual(summarize_list(elem.findall(".//section[tag = 'subtext']")),
    282                           ['section', 'section'])
    283          self.assertEqual(summarize_list(elem.findall(".//tag[. = 'subtext']")),
    284                           ['tag', 'tag'])
    285          self.assertEqual(summarize_list(elem.findall(".//tag[@class][@id]")),
    286                           ['tag', 'tag'])
    287
    288
    289  #class ElementTreeElementPathTestCase(EtreeElementPathTestCase):
    290  #    import xml.etree.ElementTree as etree
    291  #    import xml.etree.ElementPath as _elementpath
    292
    293
    294 -def test_suite():
    295      suite = unittest.TestSuite()
    296      suite.addTests([unittest.makeSuite(EtreeElementPathTestCase)])
    297      #suite.addTests([unittest.makeSuite(ElementTreeElementPathTestCase)])
    298      return suite
    299
    300
    301  if __name__ == '__main__':
    302      print('to test use test.py %s' % __file__)
    303