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

Source Code for Module lxml.tests.test_xslt

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