lxml.tests.test_xslt

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