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

# Source Code for Module lxml.tests.test_xslt

       1  # -*- coding: utf-8 -*-
       2
       3  """
       4  Test cases related to XSLT processing
       5  """
       6
       7  import unittest, copy, 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  is_python3 = sys.version_info[0] >= 3
      14
      15  try:
      16      unicode
      17  except NameError: # Python 3
      18      unicode = str
      19
      20  try:
      21      basestring
      22  except NameError: # Python 3
      23      basestring = str
      24
      25  from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir
      26  from common_imports import doctest, _bytes, _str, make_doctest, skipif
      27
      28 -class ETreeXSLTTestCase(HelperTestCase):
      29      """XSLT tests etree"""
      30
      31 -    def test_xslt(self):
      32          tree = self.parse('<a><b>B</b><c>C</c></a>')
      33          style = self.parse('''\
      34  <xsl:stylesheet version="1.0"
      35      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      36    <xsl:template match="*" />
      37    <xsl:template match="/">
      38      <foo><xsl:value-of select="/a/b/text()" /></foo>
      39    </xsl:template>
      40  </xsl:stylesheet>''')
      41
      42          st = etree.XSLT(style)
      43          res = st(tree)
      44          self.assertEqual('''\
      45  <?xml version="1.0"?>
      46  <foo>B</foo>
      47  ''',
      48                            str(res))
      49
      50 -    def test_xslt_elementtree_error(self):
      51          self.assertRaises(ValueError, etree.XSLT, etree.ElementTree())
      52
      53 -    def test_xslt_input_none(self):
      54          self.assertRaises(TypeError, etree.XSLT, None)
      55
      56      if False and etree.LIBXSLT_VERSION >= (1,1,15):
      57          # earlier versions generate no error
      58          if etree.LIBXSLT_VERSION > (1,1,17):
      59 -            def test_xslt_invalid_stylesheet(self):
      60                  style = self.parse('''\
      61  <xsl:stylesheet version="1.0"
      62      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      63    <xsl:stylesheet />
      64  </xsl:stylesheet>''')
      65
      66                  self.assertRaises(
      67                      etree.XSLTParseError, etree.XSLT, style)
      68
      69 -    def test_xslt_copy(self):
      70          tree = self.parse('<a><b>B</b><c>C</c></a>')
      71          style = self.parse('''\
      72  <xsl:stylesheet version="1.0"
      73      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      74    <xsl:template match="*" />
      75    <xsl:template match="/">
      76      <foo><xsl:value-of select="/a/b/text()" /></foo>
      77    </xsl:template>
      78  </xsl:stylesheet>''')
      79
      80          transform = etree.XSLT(style)
      81          res = transform(tree)
      82          self.assertEqual('''\
      83  <?xml version="1.0"?>
      84  <foo>B</foo>
      85  ''',
      86                            str(res))
      87
      88          transform_copy = copy.deepcopy(transform)
      89          res = transform_copy(tree)
      90          self.assertEqual('''\
      91  <?xml version="1.0"?>
      92  <foo>B</foo>
      93  ''',
      94                            str(res))
      95
      96          transform = etree.XSLT(style)
      97          res = transform(tree)
      98          self.assertEqual('''\
      99  <?xml version="1.0"?>
     100  <foo>B</foo>
     101  ''',
     102                            str(res))
     103
     104 -    def test_xslt_utf8(self):
     105          tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
     106                                   ).decode("unicode_escape"))
     107          style = self.parse('''\
     108  <xsl:stylesheet version="1.0"
     109      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     110    <xsl:output encoding="UTF-8"/>
     111    <xsl:template match="/">
     112      <foo><xsl:value-of select="/a/b/text()" /></foo>
     113    </xsl:template>
     114  </xsl:stylesheet>''')
     115
     116          st = etree.XSLT(style)
     117          res = st(tree)
     118          expected = _bytes('''\
     119  <?xml version="1.0" encoding="UTF-8"?>
     120  <foo>\\uF8D2</foo>
     121  ''').decode("unicode_escape")
     122          if is_python3:
     123              self.assertEqual(expected,
     124                                str(bytes(res), 'UTF-8'))
     125          else:
     126              self.assertEqual(expected,
     127                                unicode(str(res), 'UTF-8'))
     128
     129 -    def test_xslt_encoding(self):
     130          tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
     131                                   ).decode("unicode_escape"))
     132          style = self.parse('''\
     133  <xsl:stylesheet version="1.0"
     134      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     135    <xsl:output encoding="UTF-16"/>
     136    <xsl:template match="/">
     137      <foo><xsl:value-of select="/a/b/text()" /></foo>
     138    </xsl:template>
     139  </xsl:stylesheet>''')
     140
     141          st = etree.XSLT(style)
     142          res = st(tree)
     143          expected = _bytes('''\
     144  <?xml version="1.0" encoding="UTF-16"?>
     145  <foo>\\uF8D2</foo>
     146  ''').decode("unicode_escape")
     147          if is_python3:
     148              self.assertEqual(expected,
     149                                str(bytes(res), 'UTF-16'))
     150          else:
     151              self.assertEqual(expected,
     152                                unicode(str(res), 'UTF-16'))
     153
     154 -    def test_xslt_encoding_override(self):
     155          tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
     156                                   ).decode("unicode_escape"))
     157          style = self.parse('''\
     158  <xsl:stylesheet version="1.0"
     159      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     160    <xsl:output encoding="UTF-8"/>
     161    <xsl:template match="/">
     162      <foo><xsl:value-of select="/a/b/text()" /></foo>
     163    </xsl:template>
     164  </xsl:stylesheet>''')
     165
     166          st = etree.XSLT(style)
     167          res = st(tree)
     168          expected = _bytes("""\
     169  <?xml version='1.0' encoding='UTF-16'?>\
     170  <foo>\\uF8D2</foo>""").decode("unicode_escape")
     171
     172          f = BytesIO()
     173          res.write(f, encoding='UTF-16')
     174          if is_python3:
     175              result = str(f.getvalue(), 'UTF-16').replace('\n', '')
     176          else:
     177              result = unicode(str(f.getvalue()), 'UTF-16').replace('\n', '')
     178          self.assertEqual(expected, result)
     179
     180 -    def test_xslt_unicode(self):
     181          tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
     182                                   ).decode("unicode_escape"))
     183          style = self.parse('''\
     184  <xsl:stylesheet version="1.0"
     185      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     186    <xsl:output encoding="UTF-16"/>
     187    <xsl:template match="/">
     188      <foo><xsl:value-of select="/a/b/text()" /></foo>
     189    </xsl:template>
     190  </xsl:stylesheet>''')
     191
     192          st = etree.XSLT(style)
     193          res = st(tree)
     194          expected = _bytes('''\
     195  <?xml version="1.0"?>
     196  <foo>\\uF8D2</foo>
     197  ''').decode("unicode_escape")
     198          self.assertEqual(expected,
     199                            unicode(res))
     200
     201 -    def test_xslt_input(self):
     202          style = self.parse('''\
     203  <xsl:stylesheet version="1.0"
     204      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     205    <xsl:template match="*" />
     206    <xsl:template match="/">
     207      <foo><xsl:value-of select="/a/b/text()" /></foo>
     208    </xsl:template>
     209  </xsl:stylesheet>''')
     210
     211          st = etree.XSLT(style)
     212          st = etree.XSLT(style.getroot())
     213
     214 -    def test_xslt_input_partial_doc(self):
     215          style = self.parse('''\
     216  <otherroot>
     217  <xsl:stylesheet version="1.0"
     218      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     219    <xsl:template match="*" />
     220    <xsl:template match="/">
     221      <foo><xsl:value-of select="/a/b/text()" /></foo>
     222    </xsl:template>
     223  </xsl:stylesheet>
     224  </otherroot>''')
     225
     226          self.assertRaises(etree.XSLTParseError, etree.XSLT, style)
     227          root_node = style.getroot()
     228          self.assertRaises(etree.XSLTParseError, etree.XSLT, root_node)
     229          st = etree.XSLT(root_node[0])
     230
     231 -    def test_xslt_broken(self):
     232          tree = self.parse('<a/>')
     233          style = self.parse('''\
     234  <xsl:stylesheet version="1.0"
     235      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     236      <xsl:foo />
     237  </xsl:stylesheet>''')
     238          self.assertRaises(etree.XSLTParseError,
     239                            etree.XSLT, style)
     240
     241 -    def test_xslt_parameters(self):
     242          tree = self.parse('<a><b>B</b><c>C</c></a>')
     243          style = self.parse('''\
     244  <xsl:stylesheet version="1.0"
     245      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     246    <xsl:template match="/">
     247      <foo><xsl:value-of select="$bar" /></foo>
     248    </xsl:template>
     249  </xsl:stylesheet>''')
     250
     251          st = etree.XSLT(style)
     252          res = st(tree, bar="'Bar'")
     253          self.assertEqual('''\
     254  <?xml version="1.0"?>
     255  <foo>Bar</foo>
     256  ''',
     257                            str(res))
     258
     259 -    def test_xslt_string_parameters(self):
     260          tree = self.parse('<a><b>B</b><c>C</c></a>')
     261          style = self.parse('''\
     262  <xsl:stylesheet version="1.0"
     263      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     264    <xsl:template match="/">
     265      <foo><xsl:value-of select="$bar" /></foo>
     266    </xsl:template>
     267  </xsl:stylesheet>''')
     268
     269          st = etree.XSLT(style)
     270          res = st(tree, bar=etree.XSLT.strparam('''it's me, "Bar"'''))
     271          self.assertEqual('''\
     272  <?xml version="1.0"?>
     273  <foo>it's me, "Bar"</foo>
     274  ''',
     275                            str(res))
     276
     277 -    def test_xslt_parameter_invalid(self):
     278          tree = self.parse('<a><b>B</b><c>C</c></a>')
     279          style = self.parse('''\
     280  <xsl:stylesheet version="1.0"
     281      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     282    <xsl:param name="bar"/>
     283    <xsl:template match="/">
     284      <foo><xsl:value-of select="$bar" /></foo>
     285    </xsl:template>
     286  </xsl:stylesheet>''')
     287
     288          st = etree.XSLT(style)
     289          res = self.assertRaises(etree.XSLTApplyError,
     290                                  st, tree, bar="<test/>")
     291          res = self.assertRaises(etree.XSLTApplyError,
     292                                  st, tree, bar="....")
     293
     294      if etree.LIBXSLT_VERSION < (1,1,18):
     295          # later versions produce no error
     296 -        def test_xslt_parameter_missing(self):
     297              # apply() without needed parameter will lead to XSLTApplyError
     298              tree = self.parse('<a><b>B</b><c>C</c></a>')
     299              style = self.parse('''\
     300  <xsl:stylesheet version="1.0"
     301      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     302    <xsl:template match="/">
     303      <foo><xsl:value-of select="$bar" /></foo>
     304    </xsl:template>
     305  </xsl:stylesheet>''')
     306
     307              st = etree.XSLT(style)
     308              self.assertRaises(etree.XSLTApplyError,
     309                                st.apply, tree)
     310
     311 -    def test_xslt_multiple_parameters(self):
     312          tree = self.parse('<a><b>B</b><c>C</c></a>')
     313          style = self.parse('''\
     314  <xsl:stylesheet version="1.0"
     315      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     316    <xsl:template match="*" />
     317    <xsl:template match="/">
     318      <foo><xsl:value-of select="$bar" /></foo>
     319      <foo><xsl:value-of select="$baz" /></foo>
     320    </xsl:template>
     321  </xsl:stylesheet>''')
     322
     323          st = etree.XSLT(style)
     324          res = st(tree, bar="'Bar'", baz="'Baz'")
     325          self.assertEqual('''\
     326  <?xml version="1.0"?>
     327  <foo>Bar</foo><foo>Baz</foo>
     328  ''',
     329                            str(res))
     330
     331 -    def test_xslt_parameter_xpath(self):
     332          tree = self.parse('<a><b>B</b><c>C</c></a>')
     333          style = self.parse('''\
     334  <xsl:stylesheet version="1.0"
     335      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     336    <xsl:template match="*" />
     337    <xsl:template match="/">
     338      <foo><xsl:value-of select="$bar" /></foo>
     339    </xsl:template>
     340  </xsl:stylesheet>''')
     341
     342          st = etree.XSLT(style)
     343          res = st(tree, bar="/a/b/text()")
     344          self.assertEqual('''\
     345  <?xml version="1.0"?>
     346  <foo>B</foo>
     347  ''',
     348                            str(res))
     349
     350 -    def test_xslt_parameter_xpath_object(self):
     351          tree = self.parse('<a><b>B</b><c>C</c></a>')
     352          style = self.parse('''\
     353  <xsl:stylesheet version="1.0"
     354      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     355    <xsl:template match="*" />
     356    <xsl:template match="/">
     357      <foo><xsl:value-of select="$bar" /></foo>
     358    </xsl:template>
     359  </xsl:stylesheet>''')
     360
     361          st = etree.XSLT(style)
     362          res = st(tree, bar=etree.XPath("/a/b/text()"))
     363          self.assertEqual('''\
     364  <?xml version="1.0"?>
     365  <foo>B</foo>
     366  ''',
     367                            str(res))
     368
     369 -    def test_xslt_default_parameters(self):
     370          tree = self.parse('<a><b>B</b><c>C</c></a>')
     371          style = self.parse('''\
     372  <xsl:stylesheet version="1.0"
     373      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     374    <xsl:param name="bar" select="'Default'" />
     375    <xsl:template match="*" />
     376    <xsl:template match="/">
     377      <foo><xsl:value-of select="$bar" /></foo>
     378    </xsl:template>
     379  </xsl:stylesheet>''')
     380
     381          st = etree.XSLT(style)
     382          res = st(tree, bar="'Bar'")
     383          self.assertEqual('''\
     384  <?xml version="1.0"?>
     385  <foo>Bar</foo>
     386  ''',
     387                            str(res))
     388          res = st(tree)
     389          self.assertEqual('''\
     390  <?xml version="1.0"?>
     391  <foo>Default</foo>
     392  ''',
     393                            str(res))
     394
     395 -    def test_xslt_html_output(self):
     396          tree = self.parse('<a><b>B</b><c>C</c></a>')
     397          style = self.parse('''\
     398  <xsl:stylesheet version="1.0"
     399      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     400    <xsl:output method="html"/>
     401    <xsl:strip-space elements="*"/>
     402    <xsl:template match="/">
     403      <html><body><xsl:value-of select="/a/b/text()" /></body></html>
     404    </xsl:template>
     405  </xsl:stylesheet>''')
     406
     407          st = etree.XSLT(style)
     408          res = st(tree)
     409          self.assertEqual('<html><body>B</body></html>',
     410                            str(res).strip())
     411
     412 -    def test_xslt_include(self):
     413          tree = etree.parse(fileInTestDir('test1.xslt'))
     414          st = etree.XSLT(tree)
     415
     416 -    def test_xslt_include_from_filelike(self):
     417          f = open(fileInTestDir('test1.xslt'), 'rb')
     418          tree = etree.parse(f)
     419          f.close()
     420          st = etree.XSLT(tree)
     421
     422 -    def test_xslt_multiple_transforms(self):
     423          xml = '<a/>'
     424          xslt = '''\
     425  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     426      <xsl:template match="/">
     427          <response>Some text</response>
     428      </xsl:template>
     429  </xsl:stylesheet>
     430  '''
     431          source = self.parse(xml)
     432          styledoc = self.parse(xslt)
     433          style = etree.XSLT(styledoc)
     434          result = style(source)
     435
     436          etree.tostring(result.getroot())
     437
     438          source = self.parse(xml)
     439          styledoc = self.parse(xslt)
     440          style = etree.XSLT(styledoc)
     441          result = style(source)
     442
     443          etree.tostring(result.getroot())
     444
     445 -    def test_xslt_repeat_transform(self):
     446          xml = '<a/>'
     447          xslt = '''\
     448  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     449      <xsl:template match="/">
     450          <response>Some text</response>
     451      </xsl:template>
     452  </xsl:stylesheet>
     453  '''
     454          source = self.parse(xml)
     455          styledoc = self.parse(xslt)
     456          transform = etree.XSLT(styledoc)
     457          result = transform(source)
     458          result = transform(source)
     459          etree.tostring(result.getroot())
     460          result = transform(source)
     461          etree.tostring(result.getroot())
     462          str(result)
     463
     464          result1 = transform(source)
     465          result2 = transform(source)
     466          self.assertEqual(str(result1), str(result2))
     467          result = transform(source)
     468          str(result)
     469
     470 -    def test_xslt_empty(self):
     471          # could segfault if result contains "empty document"
     472          xml = '<blah/>'
     473          xslt = '''
     474          <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     475            <xsl:template match="/" />
     476          </xsl:stylesheet>
     477          '''
     478
     479          source = self.parse(xml)
     480          styledoc = self.parse(xslt)
     481          style = etree.XSLT(styledoc)
     482          result = style(source)
     483          self.assertEqual('', str(result))
     484
     485 -    def test_xslt_message(self):
     486          xml = '<blah/>'
     487          xslt = '''
     488          <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     489            <xsl:template match="/">
     490              <xsl:message>TEST TEST TEST</xsl:message>
     491            </xsl:template>
     492          </xsl:stylesheet>
     493          '''
     494
     495          source = self.parse(xml)
     496          styledoc = self.parse(xslt)
     497          style = etree.XSLT(styledoc)
     498          result = style(source)
     499          self.assertEqual('', str(result))
     500          self.assertTrue("TEST TEST TEST" in [entry.message
     501                                            for entry in style.error_log])
     502
     503 -    def test_xslt_message_terminate(self):
     504          xml = '<blah/>'
     505          xslt = '''
     506          <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
     507            <xsl:template match="/">
     508              <xsl:message terminate="yes">TEST TEST TEST</xsl:message>
     509            </xsl:template>
     510          </xsl:stylesheet>
     511          '''
     512
     513          source = self.parse(xml)
     514          styledoc = self.parse(xslt)
     515          style = etree.XSLT(styledoc)
     516
     517          self.assertRaises(etree.XSLTApplyError, style, source)
     518          self.assertTrue("TEST TEST TEST" in [entry.message
     519                                            for entry in style.error_log])
     520
     521 -    def test_xslt_shortcut(self):
     522          tree = self.parse('<a><b>B</b><c>C</c></a>')
     523          style = self.parse('''\
     524  <xsl:stylesheet version="1.0"
     525      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     526    <xsl:template match="*" />
     527    <xsl:template match="/">
     528      <doc>
     529      <foo><xsl:value-of select="$bar" /></foo>
     530      <foo><xsl:value-of select="$baz" /></foo>
     531      </doc>
     532    </xsl:template>
     533  </xsl:stylesheet>''')
     534
     535          result = tree.xslt(style, bar="'Bar'", baz="'Baz'")
     536          self.assertEqual(
     537              _bytes('<doc><foo>Bar</foo><foo>Baz</foo></doc>'),
     538              etree.tostring(result.getroot()))
     539
     540 -    def test_multiple_elementrees(self):
     541          tree = self.parse('<a><b>B</b><c>C</c></a>')
     542          style = self.parse('''\
     543  <xsl:stylesheet version="1.0"
     544      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     545    <xsl:template match="a"><A><xsl:apply-templates/></A></xsl:template>
     546    <xsl:template match="b"><B><xsl:apply-templates/></B></xsl:template>
     547    <xsl:template match="c"><C><xsl:apply-templates/></C></xsl:template>
     548  </xsl:stylesheet>''')
     549
     550          self.assertEqual(self._rootstring(tree),
     551                            _bytes('<a><b>B</b><c>C</c></a>'))
     552          result = tree.xslt(style)
     553          self.assertEqual(self._rootstring(tree),
     554                            _bytes('<a><b>B</b><c>C</c></a>'))
     555          self.assertEqual(self._rootstring(result),
     556                            _bytes('<A><B>B</B><C>C</C></A>'))
     557
     558          b_tree = etree.ElementTree(tree.getroot()[0])
     559          self.assertEqual(self._rootstring(b_tree),
     560                            _bytes('<b>B</b>'))
     561          result = b_tree.xslt(style)
     562          self.assertEqual(self._rootstring(tree),
     563                            _bytes('<a><b>B</b><c>C</c></a>'))
     564          self.assertEqual(self._rootstring(result),
     565                            _bytes('<B>B</B>'))
     566
     567          c_tree = etree.ElementTree(tree.getroot()[1])
     568          self.assertEqual(self._rootstring(c_tree),
     569                            _bytes('<c>C</c>'))
     570          result = c_tree.xslt(style)
     571          self.assertEqual(self._rootstring(tree),
     572                            _bytes('<a><b>B</b><c>C</c></a>'))
     573          self.assertEqual(self._rootstring(result),
     574                            _bytes('<C>C</C>'))
     575
     576 -    def test_xslt_document_XML(self):
     577          # make sure document('') works from parsed strings
     578          xslt = etree.XSLT(etree.XML("""\
     579  <xsl:stylesheet version="1.0"
     580     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     581    <xsl:template match="/">
     582      <test>TEXT<xsl:copy-of select="document('')//test"/></test>
     583    </xsl:template>
     584  </xsl:stylesheet>
     585  """))
     586          result = xslt(etree.XML('<a/>'))
     587          root = result.getroot()
     588          self.assertEqual(root.tag,
     589                            'test')
     590          self.assertEqual(root[0].tag,
     591                            'test')
     592          self.assertEqual(root[0].text,
     593                            'TEXT')
     594          self.assertEqual(root[0][0].tag,
     595                            '{http://www.w3.org/1999/XSL/Transform}copy-of')
     596
     597 -    def test_xslt_document_parse(self):
     598          # make sure document('') works from loaded files
     599          xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt")))
     600          result = xslt(etree.XML('<a/>'))
     601          root = result.getroot()
     602          self.assertEqual(root.tag,
     603                            'test')
     604          self.assertEqual(root[0].tag,
     605                            '{http://www.w3.org/1999/XSL/Transform}stylesheet')
     606
     607 -    def test_xslt_document_elementtree(self):
     608          # make sure document('') works from loaded files
     609          xslt = etree.XSLT(etree.ElementTree(file=fileInTestDir("test-document.xslt")))
     610          result = xslt(etree.XML('<a/>'))
     611          root = result.getroot()
     612          self.assertEqual(root.tag,
     613                            'test')
     614          self.assertEqual(root[0].tag,
     615                            '{http://www.w3.org/1999/XSL/Transform}stylesheet')
     616
     617 -    def test_xslt_document_error(self):
     618          xslt = etree.XSLT(etree.XML("""\
     619  <xsl:stylesheet version="1.0"
     620     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     621    <xsl:template match="/">
     622      <test>TEXT<xsl:copy-of select="document('uri:__junkfood__is__evil__')//test"/></test>
     623    </xsl:template>
     624  </xsl:stylesheet>
     625  """))
     626          self.assertRaises(etree.XSLTApplyError, xslt, etree.XML('<a/>'))
     627
     628 -    def test_xslt_document_XML_resolver(self):
     629          # make sure document('') works when custom resolvers are in use
     630          assertEqual = self.assertEqual
     631          called = {'count' : 0}
     632          class TestResolver(etree.Resolver):
     633              def resolve(self, url, id, context):
     634                  assertEqual(url, 'file://ANYTHING')
     635                  called['count'] += 1
     636                  return self.resolve_string('<CALLED/>', context)
     637
     638          parser = etree.XMLParser()
     639          parser.resolvers.add(TestResolver())
     640
     641          xslt = etree.XSLT(etree.XML(_bytes("""\
     642  <xsl:stylesheet version="1.0"
     643     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     644     xmlns:l="local">
     645    <xsl:template match="/">
     646      <test>
     647        <xsl:for-each select="document('')//l:data/l:entry">
     648          <xsl:copy-of select="document('file://ANYTHING')"/>
     649          <xsl:copy>
     650            <xsl:attribute name="value">
     651              <xsl:value-of select="."/>
     652            </xsl:attribute>
     653          </xsl:copy>
     654        </xsl:for-each>
     655      </test>
     656    </xsl:template>
     657    <l:data>
     658      <l:entry>A</l:entry>
     659      <l:entry>B</l:entry>
     660    </l:data>
     661  </xsl:stylesheet>
     662  """), parser))
     663
     664          self.assertEqual(called['count'], 0)
     665          result = xslt(etree.XML('<a/>'))
     666          self.assertEqual(called['count'], 1)
     667
     668          root = result.getroot()
     669          self.assertEqual(root.tag,
     670                            'test')
     671          self.assertEqual(len(root), 4)
     672
     673          self.assertEqual(root[0].tag,
     674                            'CALLED')
     675          self.assertEqual(root[1].tag,
     676                            '{local}entry')
     677          self.assertEqual(root[1].text,
     678                            None)
     679          self.assertEqual(root[1].get("value"),
     680                            'A')
     681          self.assertEqual(root[2].tag,
     682                            'CALLED')
     683          self.assertEqual(root[3].tag,
     684                            '{local}entry')
     685          self.assertEqual(root[3].text,
     686                            None)
     687          self.assertEqual(root[3].get("value"),
     688                            'B')
     689
     690 -    def test_xslt_resolver_url_building(self):
     691          assertEqual = self.assertEqual
     692          called = {'count' : 0}
     693          expected_url = None
     694          class TestResolver(etree.Resolver):
     695              def resolve(self, url, id, context):
     696                  assertEqual(url, expected_url)
     697                  called['count'] += 1
     698                  return self.resolve_string('<CALLED/>', context)
     699
     700          stylesheet_xml = _bytes("""\
     701  <xsl:stylesheet version="1.0"
     702     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     703     xmlns:l="local">
     704    <xsl:template match="/">
     705      <xsl:copy-of select="document('test.xml')"/>
     706    </xsl:template>
     707  </xsl:stylesheet>
     708  """)
     709
     710          parser = etree.XMLParser()
     711          parser.resolvers.add(TestResolver())
     712
     713          # test without base_url => relative path only
     714          expected_url = 'test.xml'
     715          xslt = etree.XSLT(etree.XML(stylesheet_xml, parser))
     716
     717          self.assertEqual(called['count'], 0)
     718          result = xslt(etree.XML('<a/>'))
     719          self.assertEqual(called['count'], 1)
     720
     721          # now the same thing with a stylesheet base URL on the filesystem
     722          called['count'] = 0
     723          expected_url = os.path.join('MY', 'BASE', 'test.xml')
     724          xslt = etree.XSLT(etree.XML(stylesheet_xml, parser,
     725                                      base_url=os.path.join('MY', 'BASE', 'FILE')))
     726
     727          self.assertEqual(called['count'], 0)
     728          result = xslt(etree.XML('<a/>'))
     729          self.assertEqual(called['count'], 1)
     730
     731          # now the same thing with a stylesheet base URL
     732          called['count'] = 0
     733          expected_url = 'http://server.com/BASE/DIR/test.xml'
     734          xslt = etree.XSLT(etree.XML(stylesheet_xml, parser,
     735                                      base_url='http://server.com/BASE/DIR/FILE'))
     736
     737          self.assertEqual(called['count'], 0)
     738          result = xslt(etree.XML('<a/>'))
     739          self.assertEqual(called['count'], 1)
     740
     741 -    def test_xslt_document_parse_allow(self):
     742          access_control = etree.XSLTAccessControl(read_file=True)
     743          xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt")),
     744                            access_control = access_control)
     745          result = xslt(etree.XML('<a/>'))
     746          root = result.getroot()
     747          self.assertEqual(root.tag,
     748                            'test')
     749          self.assertEqual(root[0].tag,
     750                            '{http://www.w3.org/1999/XSL/Transform}stylesheet')
     751
     752 -    def test_xslt_document_parse_deny(self):
     753          access_control = etree.XSLTAccessControl(read_file=False)
     754          xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt")),
     755                            access_control = access_control)
     756          self.assertRaises(etree.XSLTApplyError, xslt, etree.XML('<a/>'))
     757
     758 -    def test_xslt_document_parse_deny_all(self):
     759          access_control = etree.XSLTAccessControl.DENY_ALL
     760          xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt")),
     761                            access_control = access_control)
     762          self.assertRaises(etree.XSLTApplyError, xslt, etree.XML('<a/>'))
     763
     764 -    def test_xslt_move_result(self):
     765          root = etree.XML(_bytes('''\
     766          <transform>
     767            <widget displayType="fieldset"/>
     768          </transform>'''))
     769
     770          xslt = etree.XSLT(etree.XML(_bytes('''\
     771          <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     772            <xsl:output method="html" indent="no"/>
     773            <xsl:template match="/">
     774              <html>
     775                <xsl:apply-templates/>
     776              </html>
     777            </xsl:template>
     778
     779            <xsl:template match="widget">
     780              <xsl:element name="{@displayType}"/>
     781            </xsl:template>
     782
     783          </xsl:stylesheet>''')))
     784
     785          result = xslt(root[0])
     786          root[:] = result.getroot()[:]
     787          del root # segfaulted before
     788
     789 -    def test_xslt_pi(self):
     790          tree = self.parse('''\
     791  <?xml version="1.0"?>
     792  <?xml-stylesheet type="text/xsl" href="%s"?>
     793  <a>
     794    <b>B</b>
     795    <c>C</c>
     796  </a>''' % fileInTestDir("test1.xslt"))
     797
     798          style_root = tree.getroot().getprevious().parseXSL().getroot()
     799          self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
     800                            style_root.tag)
     801
     802 -    def test_xslt_pi_embedded_xmlid(self):
     803          # test xml:id dictionary lookup mechanism
     804          tree = self.parse('''\
     805  <?xml version="1.0"?>
     806  <?xml-stylesheet type="text/xsl" href="#style"?>
     807  <a>
     808    <b>B</b>
     809    <c>C</c>
     810    <xsl:stylesheet version="1.0" xml:id="style"
     811        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     812      <xsl:template match="*" />
     813      <xsl:template match="/">
     814        <foo><xsl:value-of select="/a/b/text()" /></foo>
     815      </xsl:template>
     816    </xsl:stylesheet>
     817  </a>''')
     818
     819          style_root = tree.getroot().getprevious().parseXSL().getroot()
     820          self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
     821                            style_root.tag)
     822
     823          st = etree.XSLT(style_root)
     824          res = st(tree)
     825          self.assertEqual('''\
     826  <?xml version="1.0"?>
     827  <foo>B</foo>
     828  ''',
     829                            str(res))
     830
     831 -    def test_xslt_pi_embedded_id(self):
     832          # test XPath lookup mechanism
     833          tree = self.parse('''\
     834  <?xml version="1.0"?>
     835  <?xml-stylesheet type="text/xsl" href="#style"?>
     836  <a>
     837    <b>B</b>
     838    <c>C</c>
     839  </a>''')
     840
     841          style = self.parse('''\
     842  <xsl:stylesheet version="1.0" xml:id="style"
     843      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     844    <xsl:template match="*" />
     845    <xsl:template match="/">
     846      <foo><xsl:value-of select="/a/b/text()" /></foo>
     847    </xsl:template>
     848  </xsl:stylesheet>
     849  ''')
     850
     851          tree.getroot().append(style.getroot())
     852
     853          style_root = tree.getroot().getprevious().parseXSL().getroot()
     854          self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
     855                            style_root.tag)
     856
     857          st = etree.XSLT(style_root)
     858          res = st(tree)
     859          self.assertEqual('''\
     860  <?xml version="1.0"?>
     861  <foo>B</foo>
     862  ''',
     863                            str(res))
     864
     865 -    def test_xslt_pi_get(self):
     866          tree = self.parse('''\
     867  <?xml version="1.0"?>
     868  <?xml-stylesheet type="text/xsl" href="TEST"?>
     869  <a>
     870    <b>B</b>
     871    <c>C</c>
     872  </a>''')
     873
     874          pi = tree.getroot().getprevious()
     875          self.assertEqual("TEST", pi.get("href"))
     876
     877 -    def test_xslt_pi_get_all(self):
     878          tree = self.parse('''\
     879  <?xml version="1.0"?>
     880  <?xml-stylesheet type="text/xsl" href="TEST"?>
     881  <a>
     882    <b>B</b>
     883    <c>C</c>
     884  </a>''')
     885
     886          pi = tree.getroot().getprevious()
     887          self.assertEqual("TEST", pi.get("href"))
     888          self.assertEqual("text/xsl", pi.get("type"))
     889          self.assertEqual(None, pi.get("motz"))
     890
     891 -    def test_xslt_pi_get_all_reversed(self):
     892          tree = self.parse('''\
     893  <?xml version="1.0"?>
     894  <?xml-stylesheet href="TEST" type="text/xsl"?>
     895  <a>
     896    <b>B</b>
     897    <c>C</c>
     898  </a>''')
     899
     900          pi = tree.getroot().getprevious()
     901          self.assertEqual("TEST", pi.get("href"))
     902          self.assertEqual("text/xsl", pi.get("type"))
     903          self.assertEqual(None, pi.get("motz"))
     904
     905 -    def test_xslt_pi_get_unknown(self):
     906          tree = self.parse('''\
     907  <?xml version="1.0"?>
     908  <?xml-stylesheet type="text/xsl" href="TEST"?>
     909  <a>
     910    <b>B</b>
     911    <c>C</c>
     912  </a>''')
     913
     914          pi = tree.getroot().getprevious()
     915          self.assertEqual(None, pi.get("unknownattribute"))
     916
     917 -    def test_xslt_pi_set_replace(self):
     918          tree = self.parse('''\
     919  <?xml version="1.0"?>
     920  <?xml-stylesheet type="text/xsl" href="TEST"?>
     921  <a>
     922    <b>B</b>
     923    <c>C</c>
     924  </a>''')
     925
     926          pi = tree.getroot().getprevious()
     927          self.assertEqual("TEST", pi.get("href"))
     928
     929          pi.set("href", "TEST123")
     930          self.assertEqual("TEST123", pi.get("href"))
     931
     932 -    def test_xslt_pi_set_new(self):
     933          tree = self.parse('''\
     934  <?xml version="1.0"?>
     935  <?xml-stylesheet type="text/xsl"?>
     936  <a>
     937    <b>B</b>
     938    <c>C</c>
     939  </a>''')
     940
     941          pi = tree.getroot().getprevious()
     942          self.assertEqual(None, pi.get("href"))
     943
     944          pi.set("href", "TEST")
     945          self.assertEqual("TEST", pi.get("href"))
     946
     947 -class ETreeEXSLTTestCase(HelperTestCase):
     948      """EXSLT tests"""
     949
     950 -    def test_exslt_str(self):
     951          tree = self.parse('<a><b>B</b><c>C</c></a>')
     952          style = self.parse('''\
     953  <xsl:stylesheet version="1.0"
     954      xmlns:str="http://exslt.org/strings"
     955      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     956      exclude-result-prefixes="str xsl">
     957    <xsl:template match="text()">
     958      <xsl:value-of select="str:align(string(.), '***', 'center')" />
     959    </xsl:template>
     960    <xsl:template match="*">
     961      <xsl:copy>
     962        <xsl:apply-templates/>
     963      </xsl:copy>
     964    </xsl:template>
     965  </xsl:stylesheet>''')
     966
     967          st = etree.XSLT(style)
     968          res = st(tree)
     969          self.assertEqual('''\
     970  <?xml version="1.0"?>
     971  <a><b>*B*</b><c>*C*</c></a>
     972  ''',
     973                            str(res))
     974
     975      if etree.LIBXSLT_VERSION >= (1,1,21):
     976 -        def test_exslt_str_attribute_replace(self):
     977              tree = self.parse('<a><b>B</b><c>C</c></a>')
     978              style = self.parse('''\
     979        <xsl:stylesheet version = "1.0"
     980            xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
     981            xmlns:str="http://exslt.org/strings"
     982            extension-element-prefixes="str">
     983
     984            <xsl:template match="/">
     985              <h1 class="{str:replace('abc', 'b', 'x')}">test</h1>
     986            </xsl:template>
     987
     988        </xsl:stylesheet>''')
     989
     990              st = etree.XSLT(style)
     991              res = st(tree)
     992              self.assertEqual('''\
     993  <?xml version="1.0"?>
     994  <h1 class="axc">test</h1>
     995  ''',
     996                                str(res))
     997
     998 -    def test_exslt_math(self):
     999          tree = self.parse('<a><b>B</b><c>C</c></a>')
    1000          style = self.parse('''\
    1001  <xsl:stylesheet version="1.0"
    1002      xmlns:math="http://exslt.org/math"
    1003      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1004      exclude-result-prefixes="math xsl">
    1005    <xsl:template match="*">
    1006      <xsl:copy>
    1007        <xsl:attribute name="pi">
    1008          <xsl:value-of select="math:constant('PI', count(*)+2)"/>
    1009        </xsl:attribute>
    1010        <xsl:apply-templates/>
    1011      </xsl:copy>
    1012    </xsl:template>
    1013  </xsl:stylesheet>''')
    1014
    1015          st = etree.XSLT(style)
    1016          res = st(tree)
    1017          self.assertEqual('''\
    1018  <?xml version="1.0"?>
    1019  <a pi="3.14"><b pi="3">B</b><c pi="3">C</c></a>
    1020  ''',
    1021                            str(res))
    1022
    1023 -    def test_exslt_regexp_test(self):
    1024          xslt = etree.XSLT(etree.XML(_bytes("""\
    1025  <xsl:stylesheet version="1.0"
    1026     xmlns:regexp="http://exslt.org/regular-expressions"
    1027     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1028    <xsl:template match="*">
    1029      <test><xsl:copy-of select="*[regexp:test(string(.), '8.')]"/></test>
    1030    </xsl:template>
    1031  </xsl:stylesheet>
    1032  """)))
    1033          result = xslt(etree.XML(_bytes('<a><b>123</b><b>098</b><b>987</b></a>')))
    1034          root = result.getroot()
    1035          self.assertEqual(root.tag,
    1036                            'test')
    1037          self.assertEqual(len(root), 1)
    1038          self.assertEqual(root[0].tag,
    1039                            'b')
    1040          self.assertEqual(root[0].text,
    1041                            '987')
    1042
    1043 -    def test_exslt_regexp_replace(self):
    1044          xslt = etree.XSLT(etree.XML("""\
    1045  <xsl:stylesheet version="1.0"
    1046     xmlns:regexp="http://exslt.org/regular-expressions"
    1047     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1048    <xsl:template match="*">
    1049      <test>
    1050        <xsl:copy-of select="regexp:replace(string(.), 'd.', '',   'XX')"/>
    1051        <xsl:text>-</xsl:text>
    1052        <xsl:copy-of select="regexp:replace(string(.), 'd.', 'gi', 'XX')"/>
    1053      </test>
    1054    </xsl:template>
    1055  </xsl:stylesheet>
    1056  """))
    1057          result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
    1058          root = result.getroot()
    1059          self.assertEqual(root.tag,
    1060                            'test')
    1061          self.assertEqual(len(root), 0)
    1062          self.assertEqual(root.text, 'abXXdEeDed-abXXXXeXXd')
    1063
    1064 -    def test_exslt_regexp_match(self):
    1065          xslt = etree.XSLT(etree.XML("""\
    1066  <xsl:stylesheet version="1.0"
    1067     xmlns:regexp="http://exslt.org/regular-expressions"
    1068     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1069    <xsl:template match="*">
    1070      <test>
    1071        <test1><xsl:copy-of  select="regexp:match(string(.), 'd.')"/></test1>
    1072        <test2><xsl:copy-of  select="regexp:match(string(.), 'd.', 'g')"/></test2>
    1073        <test2i><xsl:copy-of select="regexp:match(string(.), 'd.', 'gi')"/></test2i>
    1074      </test>
    1075    </xsl:template>
    1076  </xsl:stylesheet>
    1077  """))
    1078          result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
    1079          root = result.getroot()
    1080          self.assertEqual(root.tag,  'test')
    1081          self.assertEqual(len(root), 3)
    1082
    1083          self.assertEqual(len(root[0]), 1)
    1084          self.assertEqual(root[0][0].tag, 'match')
    1085          self.assertEqual(root[0][0].text, 'dC')
    1086
    1087          self.assertEqual(len(root[1]), 2)
    1088          self.assertEqual(root[1][0].tag, 'match')
    1089          self.assertEqual(root[1][0].text, 'dC')
    1090          self.assertEqual(root[1][1].tag, 'match')
    1091          self.assertEqual(root[1][1].text, 'dE')
    1092
    1093          self.assertEqual(len(root[2]), 3)
    1094          self.assertEqual(root[2][0].tag, 'match')
    1095          self.assertEqual(root[2][0].text, 'dC')
    1096          self.assertEqual(root[2][1].tag, 'match')
    1097          self.assertEqual(root[2][1].text, 'dE')
    1098          self.assertEqual(root[2][2].tag, 'match')
    1099          self.assertEqual(root[2][2].text, 'De')
    1100
    1101 -    def test_exslt_regexp_match_groups(self):
    1102          xslt = etree.XSLT(etree.XML(_bytes("""\
    1103  <xsl:stylesheet version="1.0"
    1104     xmlns:regexp="http://exslt.org/regular-expressions"
    1105     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1106    <xsl:template match="/">
    1107      <test>
    1108        <xsl:for-each select="regexp:match(
    1109              '123abc567', '([0-9]+)([a-z]+)([0-9]+)' )">
    1110          <test1><xsl:value-of select="."/></test1>
    1111        </xsl:for-each>
    1112      </test>
    1113    </xsl:template>
    1114  </xsl:stylesheet>
    1115  """)))
    1116          result = xslt(etree.XML(_bytes('<a/>')))
    1117          root = result.getroot()
    1118          self.assertEqual(root.tag,  'test')
    1119          self.assertEqual(len(root), 4)
    1120
    1121          self.assertEqual(root[0].text, "123abc567")
    1122          self.assertEqual(root[1].text, "123")
    1123          self.assertEqual(root[2].text, "abc")
    1124          self.assertEqual(root[3].text, "567")
    1125
    1126 -    def test_exslt_regexp_match1(self):
    1127          # taken from http://www.exslt.org/regexp/functions/match/index.html
    1128          xslt = etree.XSLT(etree.XML(_bytes("""\
    1129  <xsl:stylesheet version="1.0"
    1130     xmlns:regexp="http://exslt.org/regular-expressions"
    1131     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1132    <xsl:template match="/">
    1133      <test>
    1134        <xsl:for-each select="regexp:match(
    1135              'http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml',
    1136              '(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)')">
    1137          <test1><xsl:value-of select="."/></test1>
    1138        </xsl:for-each>
    1139      </test>
    1140    </xsl:template>
    1141  </xsl:stylesheet>
    1142  """)))
    1143          result = xslt(etree.XML(_bytes('<a/>')))
    1144          root = result.getroot()
    1145          self.assertEqual(root.tag,  'test')
    1146          self.assertEqual(len(root), 5)
    1147
    1148          self.assertEqual(
    1149              root[0].text,
    1150              "http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml")
    1151          self.assertEqual(
    1152              root[1].text,
    1153              "http")
    1154          self.assertEqual(
    1155              root[2].text,
    1156              "www.bayes.co.uk")
    1157          self.assertFalse(root[3].text)
    1158          self.assertEqual(
    1159              root[4].text,
    1160              "/xml/index.xml?/xml/utils/rechecker.xml")
    1161
    1162 -    def test_exslt_regexp_match2(self):
    1163          # taken from http://www.exslt.org/regexp/functions/match/index.html
    1164          xslt = etree.XSLT(self.parse("""\
    1165  <xsl:stylesheet version="1.0"
    1166     xmlns:regexp="http://exslt.org/regular-expressions"
    1167     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1168    <xsl:template match="/">
    1169      <test>
    1170        <xsl:for-each select="regexp:match(
    1171              'This is a test string', '(\w+)', 'g')">
    1172          <test1><xsl:value-of select="."/></test1>
    1173        </xsl:for-each>
    1174      </test>
    1175    </xsl:template>
    1176  </xsl:stylesheet>
    1177  """))
    1178          result = xslt(etree.XML(_bytes('<a/>')))
    1179          root = result.getroot()
    1180          self.assertEqual(root.tag,  'test')
    1181          self.assertEqual(len(root), 5)
    1182
    1183          self.assertEqual(root[0].text, "This")
    1184          self.assertEqual(root[1].text, "is")
    1185          self.assertEqual(root[2].text, "a")
    1186          self.assertEqual(root[3].text, "test")
    1187          self.assertEqual(root[4].text, "string")
    1188
    1189 -    def _test_exslt_regexp_match3(self):
    1190          # taken from http://www.exslt.org/regexp/functions/match/index.html
    1191          # THIS IS NOT SUPPORTED!
    1192          xslt = etree.XSLT(etree.XML(_bytes("""\
    1193  <xsl:stylesheet version="1.0"
    1194     xmlns:regexp="http://exslt.org/regular-expressions"
    1195     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1196    <xsl:template match="/">
    1197      <test>
    1198        <xsl:for-each select="regexp:match(
    1199              'This is a test string', '([a-z])+ ', 'g')">
    1200          <test1><xsl:value-of select="."/></test1>
    1201        </xsl:for-each>
    1202      </test>
    1203    </xsl:template>
    1204  </xsl:stylesheet>
    1205  """)))
    1206          result = xslt(etree.XML(_bytes('<a/>')))
    1207          root = result.getroot()
    1208          self.assertEqual(root.tag,  'test')
    1209          self.assertEqual(len(root), 4)
    1210
    1211          self.assertEqual(root[0].text, "his")
    1212          self.assertEqual(root[1].text, "is")
    1213          self.assertEqual(root[2].text, "a")
    1214          self.assertEqual(root[3].text, "test")
    1215
    1216 -    def _test_exslt_regexp_match4(self):
    1217          # taken from http://www.exslt.org/regexp/functions/match/index.html
    1218          # THIS IS NOT SUPPORTED!
    1219          xslt = etree.XSLT(etree.XML(_bytes("""\
    1220  <xsl:stylesheet version="1.0"
    1221     xmlns:regexp="http://exslt.org/regular-expressions"
    1222     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1223    <xsl:template match="/">
    1224      <test>
    1225        <xsl:for-each select="regexp:match(
    1226              'This is a test string', '([a-z])+ ', 'gi')">
    1227          <test1><xsl:value-of select="."/></test1>
    1228        </xsl:for-each>
    1229      </test>
    1230    </xsl:template>
    1231  </xsl:stylesheet>
    1232  """)))
    1233          result = xslt(etree.XML(_bytes('<a/>')))
    1234          root = result.getroot()
    1235          self.assertEqual(root.tag,  'test')
    1236          self.assertEqual(len(root), 4)
    1237
    1238          self.assertEqual(root[0].text, "This")
    1239          self.assertEqual(root[1].text, "is")
    1240          self.assertEqual(root[2].text, "a")
    1241          self.assertEqual(root[3].text, "test")
    1242
    1243
    1244 -class ETreeXSLTExtFuncTestCase(HelperTestCase):
    1245      """Tests for XPath extension functions in XSLT."""
    1246
    1247 -    def test_extensions1(self):
    1248          tree = self.parse('<a><b>B</b></a>')
    1249          style = self.parse('''\
    1250  <xsl:stylesheet version="1.0"
    1251      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1252      xmlns:myns="testns"
    1253      exclude-result-prefixes="myns">
    1254    <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
    1255  </xsl:stylesheet>''')
    1256
    1257          def mytext(ctxt, values):
    1258              return 'X' * len(values)
    1259
    1260          result = tree.xslt(style, {('testns', 'mytext') : mytext})
    1261          self.assertEqual(self._rootstring(result),
    1262                            _bytes('<A>X</A>'))
    1263
    1264 -    def test_extensions2(self):
    1265          tree = self.parse('<a><b>B</b></a>')
    1266          style = self.parse('''\
    1267  <xsl:stylesheet version="1.0"
    1268      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1269      xmlns:myns="testns"
    1270      exclude-result-prefixes="myns">
    1271    <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
    1272  </xsl:stylesheet>''')
    1273
    1274          def mytext(ctxt, values):
    1275              return 'X' * len(values)
    1276
    1277          namespace = etree.FunctionNamespace('testns')
    1278          namespace['mytext'] = mytext
    1279
    1280          result = tree.xslt(style)
    1281          self.assertEqual(self._rootstring(result),
    1282                            _bytes('<A>X</A>'))
    1283
    1284 -    def test_variable_result_tree_fragment(self):
    1285          tree = self.parse('<a><b>B</b><b/></a>')
    1286          style = self.parse('''\
    1287  <xsl:stylesheet version="1.0"
    1288      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1289      xmlns:myns="testns"
    1290      exclude-result-prefixes="myns">
    1291    <xsl:template match="a">
    1292      <xsl:variable name="content">
    1293         <xsl:apply-templates/>
    1294      </xsl:variable>
    1295      <A><xsl:value-of select="myns:mytext($content)"/></A>
    1296    </xsl:template>
    1297    <xsl:template match="b"><xsl:copy>BBB</xsl:copy></xsl:template>
    1298  </xsl:stylesheet>''')
    1299
    1300          def mytext(ctxt, values):
    1301              for value in values:
    1302                  self.assertTrue(hasattr(value, 'tag'),
    1303                               "%s is not an Element" % type(value))
    1304                  self.assertEqual(value.tag, 'b')
    1305                  self.assertEqual(value.text, 'BBB')
    1306              return 'X'.join([el.tag for el in values])
    1307
    1308          namespace = etree.FunctionNamespace('testns')
    1309          namespace['mytext'] = mytext
    1310
    1311          result = tree.xslt(style)
    1312          self.assertEqual(self._rootstring(result),
    1313                            _bytes('<A>bXb</A>'))
    1314
    1315
    1316 -class ETreeXSLTExtElementTestCase(HelperTestCase):
    1317      """Tests for extension elements in XSLT."""
    1318
    1319 -    def test_extension_element(self):
    1320          tree = self.parse('<a><b>B</b></a>')
    1321          style = self.parse('''\
    1322  <xsl:stylesheet version="1.0"
    1323      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1324      xmlns:myns="testns"
    1325      extension-element-prefixes="myns"
    1326      exclude-result-prefixes="myns">
    1327    <xsl:template match="a">
    1328      <A><myns:myext>b</myns:myext></A>
    1329    </xsl:template>
    1330  </xsl:stylesheet>''')
    1331
    1332          class MyExt(etree.XSLTExtension):
    1333              def execute(self, context, self_node, input_node, output_parent):
    1334                  child = etree.Element(self_node.text)
    1335                  child.text = 'X'
    1336                  output_parent.append(child)
    1337
    1338          extensions = { ('testns', 'myext') : MyExt() }
    1339
    1340          result = tree.xslt(style, extensions=extensions)
    1341          self.assertEqual(self._rootstring(result),
    1342                            _bytes('<A><b>X</b></A>'))
    1343
    1344 -    def test_extension_element_doc_context(self):
    1345          tree = self.parse('<a><b>B</b></a>')
    1346          style = self.parse('''\
    1347  <xsl:stylesheet version="1.0"
    1348      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1349      xmlns:myns="testns"
    1350      extension-element-prefixes="myns"
    1351      exclude-result-prefixes="myns">
    1352    <xsl:template match="/">
    1353      <A><myns:myext>b</myns:myext></A>
    1354    </xsl:template>
    1355  </xsl:stylesheet>''')
    1356
    1357          tags = []
    1358
    1359          class MyExt(etree.XSLTExtension):
    1360              def execute(self, context, self_node, input_node, output_parent):
    1361                  tags.append(input_node.tag)
    1362
    1363          extensions = { ('testns', 'myext') : MyExt() }
    1364
    1365          result = tree.xslt(style, extensions=extensions)
    1366          self.assertEqual(tags, ['a'])
    1367
    1368 -    def test_extension_element_comment_pi_context(self):
    1369          tree = self.parse('<?test toast?><a><!--a comment--><?another pi?></a>')
    1370          style = self.parse('''\
    1371  <xsl:stylesheet version="1.0"
    1372      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1373      xmlns:myns="testns"
    1374      extension-element-prefixes="myns"
    1375      exclude-result-prefixes="myns">
    1376    <xsl:template match="/">
    1377      <ROOT><xsl:apply-templates /></ROOT>
    1378    </xsl:template>
    1379    <xsl:template match="comment()">
    1380      <A><myns:myext>b</myns:myext></A>
    1381    </xsl:template>
    1382    <xsl:template match="processing-instruction()">
    1383      <A><myns:myext>b</myns:myext></A>
    1384    </xsl:template>
    1385  </xsl:stylesheet>''')
    1386
    1387          text = []
    1388
    1389          class MyExt(etree.XSLTExtension):
    1390              def execute(self, context, self_node, input_node, output_parent):
    1391                  text.append(input_node.text)
    1392
    1393          extensions = { ('testns', 'myext') : MyExt() }
    1394
    1395          result = tree.xslt(style, extensions=extensions)
    1396          self.assertEqual(text, ['toast', 'a comment', 'pi'])
    1397
    1398 -    def _test_extension_element_attribute_context(self):
    1399          # currently not supported
    1400          tree = self.parse('<a test="A"><b attr="B"/></a>')
    1401          style = self.parse('''\
    1402  <xsl:stylesheet version="1.0"
    1403      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1404      xmlns:myns="testns"
    1405      extension-element-prefixes="myns"
    1406      exclude-result-prefixes="myns">
    1407    <xsl:template match="@test">
    1408      <A><myns:myext>b</myns:myext></A>
    1409    </xsl:template>
    1410    <xsl:template match="@attr">
    1411      <A><myns:myext>b</myns:myext></A>
    1412    </xsl:template>
    1413  </xsl:stylesheet>''')
    1414
    1415          text = []
    1416
    1417          class MyExt(etree.XSLTExtension):
    1418              def execute(self, context, self_node, attr_value, output_parent):
    1419                  text.append(attr_value)
    1420
    1421          extensions = { ('testns', 'myext') : MyExt() }
    1422
    1423          result = tree.xslt(style, extensions=extensions)
    1424          self.assertEqual(text, ['A', 'B'])
    1425
    1426 -    def test_extension_element_content(self):
    1427          tree = self.parse('<a><b>B</b></a>')
    1428          style = self.parse('''\
    1429  <xsl:stylesheet version="1.0"
    1430      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1431      xmlns:myns="testns"
    1432      extension-element-prefixes="myns">
    1433    <xsl:template match="a">
    1434      <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
    1435    </xsl:template>
    1436  </xsl:stylesheet>''')
    1437
    1438          class MyExt(etree.XSLTExtension):
    1439              def execute(self, context, self_node, input_node, output_parent):
    1440                  output_parent.extend(list(self_node)[1:])
    1441
    1442          extensions = { ('testns', 'myext') : MyExt() }
    1443
    1444          result = tree.xslt(style, extensions=extensions)
    1445          self.assertEqual(self._rootstring(result),
    1446                            _bytes('<A><y>Y</y><z/></A>'))
    1447
    1448 -    def test_extension_element_apply_templates(self):
    1449          tree = self.parse('<a><b>B</b></a>')
    1450          style = self.parse('''\
    1451  <xsl:stylesheet version="1.0"
    1452      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1453      xmlns:myns="testns"
    1454      extension-element-prefixes="myns">
    1455    <xsl:template match="a">
    1456      <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
    1457    </xsl:template>
    1458    <xsl:template match="x" />
    1459    <xsl:template match="z">XYZ</xsl:template>
    1460  </xsl:stylesheet>''')
    1461
    1462          class MyExt(etree.XSLTExtension):
    1463              def execute(self, context, self_node, input_node, output_parent):
    1464                  for child in self_node:
    1465                      for result in self.apply_templates(context, child):
    1466                          if isinstance(result, basestring):
    1467                              el = etree.Element("T")
    1468                              el.text = result
    1469                          else:
    1470                              el = result
    1471                          output_parent.append(el)
    1472
    1473          extensions = { ('testns', 'myext') : MyExt() }
    1474
    1475          result = tree.xslt(style, extensions=extensions)
    1476          self.assertEqual(self._rootstring(result),
    1477                            _bytes('<A><T>Y</T><T>XYZ</T></A>'))
    1478
    1479 -    def test_extension_element_apply_templates_target_node(self):
    1480          tree = self.parse('<a><b>B</b></a>')
    1481          style = self.parse('''\
    1482  <xsl:stylesheet version="1.0"
    1483      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1484      xmlns:myns="testns"
    1485      extension-element-prefixes="myns">
    1486    <xsl:template match="a">
    1487      <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
    1488    </xsl:template>
    1489    <xsl:template match="x" />
    1490    <xsl:template match="z">XYZ</xsl:template>
    1491  </xsl:stylesheet>''')
    1492
    1493          class MyExt(etree.XSLTExtension):
    1494              def execute(self, context, self_node, input_node, output_parent):
    1495                  for child in self_node:
    1496                      self.apply_templates(context, child, output_parent)
    1497
    1498          extensions = { ('testns', 'myext') : MyExt() }
    1499
    1500          result = tree.xslt(style, extensions=extensions)
    1501          self.assertEqual(self._rootstring(result),
    1502                            _bytes('<A>YXYZ</A>'))
    1503
    1504 -    def test_extension_element_apply_templates_target_node_doc(self):
    1505          tree = self.parse('<a><b>B</b></a>')
    1506          style = self.parse('''\
    1507  <xsl:stylesheet version="1.0"
    1508      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1509      xmlns:myns="testns"
    1510      extension-element-prefixes="myns">
    1511    <xsl:template match="a">
    1512      <myns:myext><x>X</x><y>Y</y><z/></myns:myext>
    1513    </xsl:template>
    1514    <xsl:template match="x"><xsl:processing-instruction name="test">TEST</xsl:processing-instruction></xsl:template>
    1515    <xsl:template match="y"><Y>XYZ</Y></xsl:template>
    1516    <xsl:template match="z"><xsl:comment>TEST</xsl:comment></xsl:template>
    1517  </xsl:stylesheet>''')
    1518
    1519          class MyExt(etree.XSLTExtension):
    1520              def execute(self, context, self_node, input_node, output_parent):
    1521                  for child in self_node:
    1522                      self.apply_templates(context, child, output_parent)
    1523
    1524          extensions = { ('testns', 'myext') : MyExt() }
    1525
    1526          result = tree.xslt(style, extensions=extensions)
    1527          self.assertEqual(etree.tostring(result),
    1528                            _bytes('<?test TEST?><Y>XYZ</Y><!--TEST-->'))
    1529
    1530 -    def test_extension_element_process_children(self):
    1531          tree = self.parse('<a><b>E</b></a>')
    1532          style = self.parse('''\
    1533  <xsl:stylesheet version="1.0"
    1534      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1535      xmlns:myns="testns"
    1536      extension-element-prefixes="myns">
    1537    <xsl:template match="a">
    1538      <xsl:variable name="testvar">yo</xsl:variable>
    1539      <A>
    1540        <myns:myext>
    1541          <xsl:attribute name="attr">
    1542            <xsl:value-of select="$testvar" />
    1543          </xsl:attribute>
    1544          <B>
    1545            <xsl:choose>
    1546              <xsl:when test="1 = 2"><C/></xsl:when>
    1547              <xsl:otherwise><D><xsl:value-of select="b/text()" /></D></xsl:otherwise>
    1548            </xsl:choose>
    1549          </B>
    1550        </myns:myext>
    1551      </A>
    1552    </xsl:template>
    1553  </xsl:stylesheet>''')
    1554
    1555          class MyExt(etree.XSLTExtension):
    1556              def execute(self, context, self_node, input_node, output_parent):
    1557                  el = etree.Element('MY')
    1558                  self.process_children(context, el)
    1559                  output_parent.append(el)
    1560
    1561          extensions = { ('testns', 'myext') : MyExt() }
    1562
    1563          result = tree.xslt(style, extensions=extensions)
    1564          self.assertEqual(self._rootstring(result),
    1565                            _bytes('<A><MYattr="yo"><B><D>E</D></B></MY></A>'))
    1566
    1567 -    def test_extension_element_process_children_to_append_only(self):
    1568          tree = self.parse('<a/>')
    1569          style = self.parse('''\
    1570  <xsl:stylesheet version="1.0"
    1571      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1572      xmlns:myns="testns"
    1573      extension-element-prefixes="myns">
    1574    <xsl:template match="a">
    1575      <myns:myext>
    1576        <A/>
    1577      </myns:myext>
    1578    </xsl:template>
    1579  </xsl:stylesheet>''')
    1580
    1581          class MyExt(etree.XSLTExtension):
    1582              def execute(self, context, self_node, input_node, output_parent):
    1583                  self.process_children(context, output_parent)
    1584
    1585          extensions = { ('testns', 'myext') : MyExt() }
    1586
    1587          result = tree.xslt(style, extensions=extensions)
    1588          self.assertEqual(self._rootstring(result),
    1589                            _bytes('<A/>'))
    1590
    1591 -    def test_extension_element_process_children_to_read_only_raise(self):
    1592          tree = self.parse('<a/>')
    1593          style = self.parse('''\
    1594  <xsl:stylesheet version="1.0"
    1595      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1596      xmlns:myns="testns"
    1597      extension-element-prefixes="myns">
    1598    <xsl:template match="a">
    1599      <myns:myext>
    1600        <A/>
    1601      </myns:myext>
    1602    </xsl:template>
    1603  </xsl:stylesheet>''')
    1604
    1605          class MyExt(etree.XSLTExtension):
    1606              def execute(self, context, self_node, input_node, output_parent):
    1607                  self.process_children(context, self_node)
    1608
    1609          extensions = { ('testns', 'myext') : MyExt() }
    1610
    1611          self.assertRaises(TypeError, tree.xslt, style, extensions=extensions)
    1612
    1613 -    def test_extension_element_process_children_with_subextension_element(self):
    1614          tree = self.parse('<a/>')
    1615          style = self.parse('''\
    1616  <xsl:stylesheet version="1.0"
    1617      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1618      xmlns:myns="testns"
    1619      extension-element-prefixes="myns">
    1620    <xsl:template match="a">
    1621      <myns:myext>
    1622        <A><myns:myext><B/></myns:myext></A>
    1623      </myns:myext>
    1624    </xsl:template>
    1625  </xsl:stylesheet>''')
    1626
    1627          class MyExt(etree.XSLTExtension):
    1628              callback_call_counter = 0
    1629              def execute(self, context, self_node, input_node, output_parent):
    1630                  self.callback_call_counter += 1
    1631                  el = etree.Element('MY', n=str(self.callback_call_counter))
    1632                  self.process_children(context, el)
    1633                  output_parent.append(el)
    1634
    1635          extensions = { ('testns', 'myext') : MyExt() }
    1636
    1637          result = tree.xslt(style, extensions=extensions)
    1638          self.assertEqual(self._rootstring(result),
    1639                            _bytes('<MYn="1"><A><MYn="2"><B/></MY></A></MY>'))
    1640
    1641 -    def test_extension_element_raise(self):
    1642          tree = self.parse('<a><b>B</b></a>')
    1643          style = self.parse('''\
    1644  <xsl:stylesheet version="1.0"
    1645      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    1646      xmlns:myns="testns"
    1647      extension-element-prefixes="myns"
    1648      exclude-result-prefixes="myns">
    1649    <xsl:template match="a">
    1650      <A><myns:myext>b</myns:myext></A>
    1651    </xsl:template>
    1652  </xsl:stylesheet>''')
    1653
    1654          class MyError(Exception):
    1655              pass
    1656
    1657          class MyExt(etree.XSLTExtension):
    1658              def execute(self, context, self_node, input_node, output_parent):
    1659                  raise MyError("expected!")
    1660
    1661          extensions = { ('testns', 'myext') : MyExt() }
    1662          self.assertRaises(MyError, tree.xslt, style, extensions=extensions)
    1663
    1664
    1665 -class Py3XSLTTestCase(HelperTestCase):
    1666      """XSLT tests for etree under Python 3"""
    1667
    1668      pytestmark = skipif('sys.version_info < (3,0)')
    1669
    1670 -    def test_xslt_result_bytes(self):
    1671          tree = self.parse('<a><b>B</b><c>C</c></a>')
    1672          style = self.parse('''\
    1673  <xsl:stylesheet version="1.0"
    1674      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1675    <xsl:template match="*" />
    1676    <xsl:template match="/">
    1677      <foo><xsl:value-of select="/a/b/text()" /></foo>
    1678    </xsl:template>
    1679  </xsl:stylesheet>''')
    1680
    1681          st = etree.XSLT(style)
    1682          res = st(tree)
    1683          self.assertEqual(_bytes('''\
    1684  <?xml version="1.0"?>
    1685  <foo>B</foo>
    1686  '''),
    1687                            bytes(res))
    1688
    1689 -    def test_xslt_result_bytearray(self):
    1690          tree = self.parse('<a><b>B</b><c>C</c></a>')
    1691          style = self.parse('''\
    1692  <xsl:stylesheet version="1.0"
    1693      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1694    <xsl:template match="*" />
    1695    <xsl:template match="/">
    1696      <foo><xsl:value-of select="/a/b/text()" /></foo>
    1697    </xsl:template>
    1698  </xsl:stylesheet>''')
    1699
    1700          st = etree.XSLT(style)
    1701          res = st(tree)
    1702          self.assertEqual(_bytes('''\
    1703  <?xml version="1.0"?>
    1704  <foo>B</foo>
    1705  '''),
    1706                            bytearray(res))
    1707
    1708 -    def test_xslt_result_memoryview(self):
    1709          tree = self.parse('<a><b>B</b><c>C</c></a>')
    1710          style = self.parse('''\
    1711  <xsl:stylesheet version="1.0"
    1712      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    1713    <xsl:template match="*" />
    1714    <xsl:template match="/">
    1715      <foo><xsl:value-of select="/a/b/text()" /></foo>
    1716    </xsl:template>
    1717  </xsl:stylesheet>''')
    1718
    1719          st = etree.XSLT(style)
    1720          res = st(tree)
    1721          self.assertEqual(_bytes('''\
    1722  <?xml version="1.0"?>
    1723  <foo>B</foo>
    1724  '''),
    1725                            bytes(memoryview(res)))
    1726
    1727
    1728 -def test_suite():
    1729      suite = unittest.TestSuite()
    1730      suite.addTests([unittest.makeSuite(ETreeXSLTTestCase)])
    1731      suite.addTests([unittest.makeSuite(ETreeEXSLTTestCase)])
    1732      suite.addTests([unittest.makeSuite(ETreeXSLTExtFuncTestCase)])
    1733      suite.addTests([unittest.makeSuite(ETreeXSLTExtElementTestCase)])
    1734      if is_python3:
    1735          suite.addTests([unittest.makeSuite(Py3XSLTTestCase)])
    1736      suite.addTests(
    1737          [make_doctest('../../../doc/extensions.txt')])
    1738      suite.addTests(
    1739          [make_doctest('../../../doc/xpathxslt.txt')])
    1740      return suite
    1741
    1742  if __name__ == '__main__':
    1743      print('to test use test.py %s' % __file__)
    1744