1   
   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)  
  12   
  13  is_python3 = sys.version_info[0] >= 3 
  14   
  15  try: 
  16      unicode 
  17  except NameError:  
  18      unicode = str 
  19   
  20  try: 
  21      basestring 
  22  except NameError:  
  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   
  29      """XSLT tests etree""" 
  30           
  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   
  52   
  55   
  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   
  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   
 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   
 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   
 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   
 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   
 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   
 231   
 248   
 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   
 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   
 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   
 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   
 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   
 333           
 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           
 345          self.assertRaises(etree.XSLTApplyError, st.apply, tree) 
  346   
 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           
 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   
 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           
 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           
 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   
 451   
 457   
 480   
 505   
 507           
 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   
 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   
 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   
 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           
 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   
 613           
 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   
 642   
 652   
 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   
 679           
 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   
 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           
 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           
 772          called['count'] = 0 
 773          expected_url = 'MY/BASE/test.xml'   
 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           
 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           
 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   
 814   
 820   
 826   
 835   
 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  
  860           
 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   
 875           
 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   
 904           
 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   
 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   
 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   
 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   
 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   
 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   
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   
1020      """EXSLT tests""" 
1021   
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   
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   
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   
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   
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   
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   
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   
1197           
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   
1233           
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   
1260           
1261           
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   
1287           
1288           
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   
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   
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   
1409           
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   
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   
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   
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   
1527           
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   
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   
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   
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   
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   
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   
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   
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   
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   
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   
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   
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       
1855       
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   
1901      """XSLT tests for etree under Python 3""" 
1902   
1903      pytestmark = skipif('sys.version_info < (3,0)') 
1904   
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   
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   
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   
1976   
1977  if __name__ == '__main__': 
1978      print('to test use test.py %s' % __file__) 
1979