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