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