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

# Source Code for Module lxml.tests.test_xslt

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