1
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)
20
21 is_python3 = sys.version_info[0] >= 3
22
23 try:
24 unicode
25 except NameError:
26 unicode = str
27
28 try:
29 basestring
30 except NameError:
31 basestring = str
32
33 from .common_imports import etree, BytesIO, HelperTestCase, fileInTestDir
34 from .common_imports import doctest, _bytes, _str, make_doctest, skipif
37 """XSLT tests etree"""
38
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
60
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
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
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
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
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
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
200
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
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
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
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
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
279
296
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
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
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
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
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
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
412
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
424 self.assertRaises(etree.XSLTApplyError, st.apply, tree)
425
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
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
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
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
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
530
536
559
584
586
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
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
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
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
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
692
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
721
731
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
758
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
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
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
851 called['count'] = 0
852 expected_url = 'MY/BASE/test.xml'
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
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
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
893
899
905
914
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
939
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
954
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
983
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
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
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
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
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
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
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
1099 """EXSLT tests"""
1100
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
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
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
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
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
1276
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
1312
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
1339
1340
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
1366
1367
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
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
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
1488
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
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
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
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
1606
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
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
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
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
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
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
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
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
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
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
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
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
1934
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
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
2016 """XSLT tests for etree under Python 3"""
2017
2018 pytestmark = skipif('sys.version_info < (3,0)')
2019
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
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
2091
2092 if __name__ == '__main__':
2093 print('to test use test.py %s' % __file__)
2094