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