1
2
3 """
4 Test cases related to XSLT processing
5 """
6
7 from __future__ import absolute_import
8
9 import io
10 import sys
11 import copy
12 import gzip
13 import os.path
14 import unittest
15 import contextlib
16 from textwrap import dedent
17 from tempfile import NamedTemporaryFile, mkdtemp
18
19 is_python3 = sys.version_info[0] >= 3
20
21 try:
22 unicode
23 except NameError:
24 unicode = str
25
26 try:
27 basestring
28 except NameError:
29 basestring = str
30
31 from .common_imports import (
32 etree, BytesIO, HelperTestCase, fileInTestDir, _bytes, make_doctest, skipif
33 )
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