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
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 contextlib.closing(gzip.GzipFile(f.name)) as f:
195 res[0] = f.read().decode("UTF-16")
196 finally:
197 os.unlink(f.name)
198
200 expected = '''
201 <?xml version="1.0"?>
202 <foo>\\uF8D2</foo>
203 '''
204 with self._xslt_setup(expected=expected) as res:
205 res[0] = unicode(res[0])
206
208 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
209 ).decode("unicode_escape"))
210 style = self.parse('''\
211 <xsl:stylesheet version="1.0"
212 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
213 <xsl:output encoding="UTF-16" standalone="no"/>
214 <xsl:template match="/">
215 <foo><xsl:value-of select="/a/b/text()" /></foo>
216 </xsl:template>
217 </xsl:stylesheet>''')
218
219 st = etree.XSLT(style)
220 res = st(tree)
221 expected = _bytes('''\
222 <?xml version="1.0" standalone="no"?>
223 <foo>\\uF8D2</foo>
224 ''').decode("unicode_escape")
225 self.assertEqual(expected,
226 unicode(res))
227
240
257
259 style = self.parse('''\
260 <xsl:stylesheet version="1.0"
261 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
262 <xsl:foo />
263 </xsl:stylesheet>''')
264 self.assertRaises(etree.XSLTParseError,
265 etree.XSLT, style)
266
268 tree = self.parse('<a/>')
269 style = self.parse('''\
270 <xsl:stylesheet version="1.0"
271 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
272 <xsl:foo />
273 </xsl:stylesheet>''')
274 self.assertRaises(etree.XSLTParseError,
275 etree.XSLT, style)
276 exc = None
277 try:
278 etree.XSLT(style)
279 except etree.XSLTParseError as e:
280 exc = e
281 else:
282 self.assertFalse(True, "XSLT processing should have failed but didn't")
283 self.assertTrue(exc is not None)
284 self.assertTrue(len(exc.error_log))
285 for error in exc.error_log:
286 self.assertTrue(':ERROR:XSLT:' in str(error))
287
289 tree = self.parse('<a/>')
290 style = self.parse('''\
291 <xsl:stylesheet version="1.0"
292 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
293 <xsl:template match="a">
294 <xsl:copy>
295 <xsl:message terminate="yes">FAIL</xsl:message>
296 </xsl:copy>
297 </xsl:template>
298 </xsl:stylesheet>''')
299 self.assertRaises(etree.XSLTApplyError,
300 etree.XSLT(style), tree)
301
302 transform = etree.XSLT(style)
303 exc = None
304 try:
305 transform(tree)
306 except etree.XSLTApplyError as e:
307 exc = e
308 else:
309 self.assertFalse(True, "XSLT processing should have failed but didn't")
310
311 self.assertTrue(exc is not None)
312 self.assertTrue(len(exc.error_log))
313 self.assertEqual(len(transform.error_log), len(exc.error_log))
314 for error in exc.error_log:
315 self.assertTrue(':ERROR:XSLT:' in str(error))
316 for error in transform.error_log:
317 self.assertTrue(':ERROR:XSLT:' in str(error))
318
320 tree = self.parse('<a><b>B</b><c>C</c></a>')
321 style = self.parse('''\
322 <xsl:stylesheet version="1.0"
323 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
324 <xsl:template match="/">
325 <foo><xsl:value-of select="$bar" /></foo>
326 </xsl:template>
327 </xsl:stylesheet>''')
328
329 st = etree.XSLT(style)
330 res = st(tree, bar="'Bar'")
331 self.assertEqual('''\
332 <?xml version="1.0"?>
333 <foo>Bar</foo>
334 ''',
335 str(res))
336
338 tree = self.parse('<a><b>B</b><c>C</c></a>')
339 style = self.parse('''\
340 <xsl:stylesheet version="1.0"
341 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
342 <xsl:template match="/">
343 <foo><xsl:value-of select="$bar" /></foo>
344 </xsl:template>
345 </xsl:stylesheet>''')
346
347 st = etree.XSLT(style)
348 res = st(tree, bar=etree.XSLT.strparam('''it's me, "Bar"'''))
349 self.assertEqual('''\
350 <?xml version="1.0"?>
351 <foo>it's me, "Bar"</foo>
352 ''',
353 str(res))
354
356 tree = self.parse('<a><b>B</b><c>C</c></a>')
357 style = self.parse('''\
358 <xsl:stylesheet version="1.0"
359 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
360 <xsl:param name="bar"/>
361 <xsl:template match="/">
362 <foo><xsl:value-of select="$bar" /></foo>
363 </xsl:template>
364 </xsl:stylesheet>''')
365
366 st = etree.XSLT(style)
367 res = self.assertRaises(etree.XSLTApplyError,
368 st, tree, bar="<test/>")
369 res = self.assertRaises(etree.XSLTApplyError,
370 st, tree, bar="....")
371
373
374 tree = self.parse('<a><b>B</b><c>C</c></a>')
375 style = self.parse('''\
376 <xsl:stylesheet version="1.0"
377 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
378 <xsl:template match="/">
379 <foo><xsl:value-of select="$bar" /></foo>
380 </xsl:template>
381 </xsl:stylesheet>''')
382
383 st = etree.XSLT(style)
384
385 self.assertRaises(etree.XSLTApplyError, st.apply, tree)
386
388 tree = self.parse('<a><b>B</b><c>C</c></a>')
389 style = self.parse('''\
390 <xsl:stylesheet version="1.0"
391 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
392 <xsl:template match="*" />
393 <xsl:template match="/">
394 <foo><xsl:value-of select="$bar" /></foo>
395 <foo><xsl:value-of select="$baz" /></foo>
396 </xsl:template>
397 </xsl:stylesheet>''')
398
399 st = etree.XSLT(style)
400 res = st(tree, bar="'Bar'", baz="'Baz'")
401 self.assertEqual('''\
402 <?xml version="1.0"?>
403 <foo>Bar</foo><foo>Baz</foo>
404 ''',
405 str(res))
406
408 tree = self.parse('<a><b>B</b><c>C</c></a>')
409 style = self.parse('''\
410 <xsl:stylesheet version="1.0"
411 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
412 <xsl:template match="*" />
413 <xsl:template match="/">
414 <foo><xsl:value-of select="$bar" /></foo>
415 </xsl:template>
416 </xsl:stylesheet>''')
417
418 st = etree.XSLT(style)
419 res = st(tree, bar="/a/b/text()")
420 self.assertEqual('''\
421 <?xml version="1.0"?>
422 <foo>B</foo>
423 ''',
424 str(res))
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 </xsl:template>
435 </xsl:stylesheet>''')
436
437 st = etree.XSLT(style)
438 res = st(tree, bar=etree.XPath("/a/b/text()"))
439 self.assertEqual('''\
440 <?xml version="1.0"?>
441 <foo>B</foo>
442 ''',
443 str(res))
444
446 tree = self.parse('<a><b>B</b><c>C</c></a>')
447 style = self.parse('''\
448 <xsl:stylesheet version="1.0"
449 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
450 <xsl:param name="bar" select="'Default'" />
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="'Bar'")
459 self.assertEqual('''\
460 <?xml version="1.0"?>
461 <foo>Bar</foo>
462 ''',
463 str(res))
464 res = st(tree)
465 self.assertEqual('''\
466 <?xml version="1.0"?>
467 <foo>Default</foo>
468 ''',
469 str(res))
470
472 tree = self.parse('<a><b>B</b><c>C</c></a>')
473 style = self.parse('''\
474 <xsl:stylesheet version="1.0"
475 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
476 <xsl:output method="html"/>
477 <xsl:strip-space elements="*"/>
478 <xsl:template match="/">
479 <html><body><xsl:value-of select="/a/b/text()" /></body></html>
480 </xsl:template>
481 </xsl:stylesheet>''')
482
483 st = etree.XSLT(style)
484 res = st(tree)
485 self.assertEqual('<html><body>B</body></html>',
486 str(res).strip())
487
491
497
520
545
547
548 xml = '<blah/>'
549 xslt = '''
550 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
551 <xsl:template match="/" />
552 </xsl:stylesheet>
553 '''
554
555 source = self.parse(xml)
556 styledoc = self.parse(xslt)
557 style = etree.XSLT(styledoc)
558 result = style(source)
559 self.assertEqual('', str(result))
560
562 xml = '<blah/>'
563 xslt = '''
564 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
565 <xsl:template match="/">
566 <xsl:message>TEST TEST TEST</xsl:message>
567 </xsl:template>
568 </xsl:stylesheet>
569 '''
570
571 source = self.parse(xml)
572 styledoc = self.parse(xslt)
573 style = etree.XSLT(styledoc)
574 result = style(source)
575 self.assertEqual('', str(result))
576 self.assertTrue("TEST TEST TEST" in [entry.message
577 for entry in style.error_log])
578
580 xml = '<blah/>'
581 xslt = '''
582 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
583 <xsl:template match="/">
584 <xsl:message terminate="yes">TEST TEST TEST</xsl:message>
585 </xsl:template>
586 </xsl:stylesheet>
587 '''
588
589 source = self.parse(xml)
590 styledoc = self.parse(xslt)
591 style = etree.XSLT(styledoc)
592
593 self.assertRaises(etree.XSLTApplyError, style, source)
594 self.assertTrue("TEST TEST TEST" in [entry.message
595 for entry in style.error_log])
596
598 tree = self.parse('<a><b>B</b><c>C</c></a>')
599 style = self.parse('''\
600 <xsl:stylesheet version="1.0"
601 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
602 <xsl:template match="*" />
603 <xsl:template match="/">
604 <doc>
605 <foo><xsl:value-of select="$bar" /></foo>
606 <foo><xsl:value-of select="$baz" /></foo>
607 </doc>
608 </xsl:template>
609 </xsl:stylesheet>''')
610
611 result = tree.xslt(style, bar="'Bar'", baz="'Baz'")
612 self.assertEqual(
613 _bytes('<doc><foo>Bar</foo><foo>Baz</foo></doc>'),
614 etree.tostring(result.getroot()))
615
617 tree = self.parse('<a><b>B</b><c>C</c></a>')
618 style = self.parse('''\
619 <xsl:stylesheet version="1.0"
620 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
621 <xsl:template match="a"><A><xsl:apply-templates/></A></xsl:template>
622 <xsl:template match="b"><B><xsl:apply-templates/></B></xsl:template>
623 <xsl:template match="c"><C><xsl:apply-templates/></C></xsl:template>
624 </xsl:stylesheet>''')
625
626 self.assertEqual(self._rootstring(tree),
627 _bytes('<a><b>B</b><c>C</c></a>'))
628 result = tree.xslt(style)
629 self.assertEqual(self._rootstring(tree),
630 _bytes('<a><b>B</b><c>C</c></a>'))
631 self.assertEqual(self._rootstring(result),
632 _bytes('<A><B>B</B><C>C</C></A>'))
633
634 b_tree = etree.ElementTree(tree.getroot()[0])
635 self.assertEqual(self._rootstring(b_tree),
636 _bytes('<b>B</b>'))
637 result = b_tree.xslt(style)
638 self.assertEqual(self._rootstring(tree),
639 _bytes('<a><b>B</b><c>C</c></a>'))
640 self.assertEqual(self._rootstring(result),
641 _bytes('<B>B</B>'))
642
643 c_tree = etree.ElementTree(tree.getroot()[1])
644 self.assertEqual(self._rootstring(c_tree),
645 _bytes('<c>C</c>'))
646 result = c_tree.xslt(style)
647 self.assertEqual(self._rootstring(tree),
648 _bytes('<a><b>B</b><c>C</c></a>'))
649 self.assertEqual(self._rootstring(result),
650 _bytes('<C>C</C>'))
651
653
654 xslt = etree.XSLT(etree.XML("""\
655 <xsl:stylesheet version="1.0"
656 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
657 <xsl:template match="/">
658 <test>TEXT<xsl:copy-of select="document('')//test"/></test>
659 </xsl:template>
660 </xsl:stylesheet>
661 """))
662 result = xslt(etree.XML('<a/>'))
663 root = result.getroot()
664 self.assertEqual(root.tag,
665 'test')
666 self.assertEqual(root[0].tag,
667 'test')
668 self.assertEqual(root[0].text,
669 'TEXT')
670 self.assertEqual(root[0][0].tag,
671 '{http://www.w3.org/1999/XSL/Transform}copy-of')
672
682
692
694 xslt = etree.XSLT(etree.XML("""\
695 <xsl:stylesheet version="1.0"
696 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
697 <xsl:template match="/">
698 <test>TEXT<xsl:copy-of select="document('uri:__junkfood__is__evil__')//test"/></test>
699 </xsl:template>
700 </xsl:stylesheet>
701 """))
702
703 errors = None
704 try:
705 xslt(etree.XML('<a/>'))
706 except etree.XSLTApplyError as exc:
707 errors = exc.error_log
708 else:
709 self.assertFalse(True, "XSLT processing should have failed but didn't")
710
711 self.assertTrue(len(errors))
712 for error in errors:
713 if ':ERROR:XSLT:' in str(error):
714 break
715 else:
716 self.assertFalse(True, 'No XSLT errors found in error log:\n%s' % errors)
717
719
720 assertEqual = self.assertEqual
721 called = {'count' : 0}
722 class TestResolver(etree.Resolver):
723 def resolve(self, url, id, context):
724 assertEqual(url, 'file://ANYTHING')
725 called['count'] += 1
726 return self.resolve_string('<CALLED/>', context)
727
728 parser = etree.XMLParser()
729 parser.resolvers.add(TestResolver())
730
731 xslt = etree.XSLT(etree.XML(_bytes("""\
732 <xsl:stylesheet version="1.0"
733 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
734 xmlns:l="local">
735 <xsl:template match="/">
736 <test>
737 <xsl:for-each select="document('')//l:data/l:entry">
738 <xsl:copy-of select="document('file://ANYTHING')"/>
739 <xsl:copy>
740 <xsl:attribute name="value">
741 <xsl:value-of select="."/>
742 </xsl:attribute>
743 </xsl:copy>
744 </xsl:for-each>
745 </test>
746 </xsl:template>
747 <l:data>
748 <l:entry>A</l:entry>
749 <l:entry>B</l:entry>
750 </l:data>
751 </xsl:stylesheet>
752 """), parser))
753
754 self.assertEqual(called['count'], 0)
755 result = xslt(etree.XML('<a/>'))
756 self.assertEqual(called['count'], 1)
757
758 root = result.getroot()
759 self.assertEqual(root.tag,
760 'test')
761 self.assertEqual(len(root), 4)
762
763 self.assertEqual(root[0].tag,
764 'CALLED')
765 self.assertEqual(root[1].tag,
766 '{local}entry')
767 self.assertEqual(root[1].text,
768 None)
769 self.assertEqual(root[1].get("value"),
770 'A')
771 self.assertEqual(root[2].tag,
772 'CALLED')
773 self.assertEqual(root[3].tag,
774 '{local}entry')
775 self.assertEqual(root[3].text,
776 None)
777 self.assertEqual(root[3].get("value"),
778 'B')
779
781 assertEqual = self.assertEqual
782 called = {'count' : 0}
783 expected_url = None
784 class TestResolver(etree.Resolver):
785 def resolve(self, url, id, context):
786 assertEqual(url, expected_url)
787 called['count'] += 1
788 return self.resolve_string('<CALLED/>', context)
789
790 stylesheet_xml = _bytes("""\
791 <xsl:stylesheet version="1.0"
792 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
793 xmlns:l="local">
794 <xsl:template match="/">
795 <xsl:copy-of select="document('test.xml')"/>
796 </xsl:template>
797 </xsl:stylesheet>
798 """)
799
800 parser = etree.XMLParser()
801 parser.resolvers.add(TestResolver())
802
803
804 expected_url = 'test.xml'
805 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser))
806
807 self.assertEqual(called['count'], 0)
808 result = xslt(etree.XML('<a/>'))
809 self.assertEqual(called['count'], 1)
810
811
812 called['count'] = 0
813 expected_url = 'MY/BASE/test.xml'
814 xslt = etree.XSLT(etree.XML(
815 stylesheet_xml, parser,
816 base_url=os.path.join('MY', 'BASE', 'FILE')))
817
818 self.assertEqual(called['count'], 0)
819 result = xslt(etree.XML('<a/>'))
820 self.assertEqual(called['count'], 1)
821
822
823 called['count'] = 0
824 expected_url = 'http://server.com/BASE/DIR/test.xml'
825 xslt = etree.XSLT(etree.XML(
826 stylesheet_xml, parser,
827 base_url='http://server.com/BASE/DIR/FILE'))
828
829 self.assertEqual(called['count'], 0)
830 result = xslt(etree.XML('<a/>'))
831 self.assertEqual(called['count'], 1)
832
833
834 called['count'] = 0
835 expected_url = 'file://BASE/DIR/test.xml'
836 xslt = etree.XSLT(etree.XML(
837 stylesheet_xml, parser,
838 base_url='file://BASE/DIR/FILE'))
839
840 self.assertEqual(called['count'], 0)
841 result = xslt(etree.XML('<a/>'))
842 self.assertEqual(called['count'], 1)
843
854
860
866
875
877 root = etree.XML(_bytes('''\
878 <transform>
879 <widget displayType="fieldset"/>
880 </transform>'''))
881
882 xslt = etree.XSLT(etree.XML(_bytes('''\
883 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
884 <xsl:output method="html" indent="no"/>
885 <xsl:template match="/">
886 <html>
887 <xsl:apply-templates/>
888 </html>
889 </xsl:template>
890
891 <xsl:template match="widget">
892 <xsl:element name="{@displayType}"/>
893 </xsl:template>
894
895 </xsl:stylesheet>''')))
896
897 result = xslt(root[0])
898 root[:] = result.getroot()[:]
899 del root
900
902 tree = self.parse('''\
903 <?xml version="1.0"?>
904 <?xml-stylesheet type="text/xsl" href="%s"?>
905 <a>
906 <b>B</b>
907 <c>C</c>
908 </a>''' % fileInTestDir("test1.xslt"))
909
910 style_root = tree.getroot().getprevious().parseXSL().getroot()
911 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
912 style_root.tag)
913
915
916 tree = self.parse('''\
917 <?xml version="1.0"?>
918 <?xml-stylesheet type="text/xsl" href="#style"?>
919 <a>
920 <b>B</b>
921 <c>C</c>
922 <xsl:stylesheet version="1.0" xml:id="style"
923 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
924 <xsl:template match="*" />
925 <xsl:template match="/">
926 <foo><xsl:value-of select="/a/b/text()" /></foo>
927 </xsl:template>
928 </xsl:stylesheet>
929 </a>''')
930
931 style_root = tree.getroot().getprevious().parseXSL().getroot()
932 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
933 style_root.tag)
934
935 st = etree.XSLT(style_root)
936 res = st(tree)
937 self.assertEqual('''\
938 <?xml version="1.0"?>
939 <foo>B</foo>
940 ''',
941 str(res))
942
944
945 tree = self.parse('''\
946 <?xml version="1.0"?>
947 <?xml-stylesheet type="text/xsl" href="#style"?>
948 <a>
949 <b>B</b>
950 <c>C</c>
951 </a>''')
952
953 style = self.parse('''\
954 <xsl:stylesheet version="1.0" xml:id="style"
955 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
956 <xsl:template match="*" />
957 <xsl:template match="/">
958 <foo><xsl:value-of select="/a/b/text()" /></foo>
959 </xsl:template>
960 </xsl:stylesheet>
961 ''')
962
963 tree.getroot().append(style.getroot())
964
965 style_root = tree.getroot().getprevious().parseXSL().getroot()
966 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
967 style_root.tag)
968
969 st = etree.XSLT(style_root)
970 res = st(tree)
971 self.assertEqual('''\
972 <?xml version="1.0"?>
973 <foo>B</foo>
974 ''',
975 str(res))
976
978 tree = self.parse('''\
979 <?xml version="1.0"?>
980 <?xml-stylesheet type="text/xsl" href="TEST"?>
981 <a>
982 <b>B</b>
983 <c>C</c>
984 </a>''')
985
986 pi = tree.getroot().getprevious()
987 self.assertEqual("TEST", pi.get("href"))
988
990 tree = self.parse('''\
991 <?xml version="1.0"?>
992 <?xml-stylesheet type="text/xsl" href="TEST"?>
993 <a>
994 <b>B</b>
995 <c>C</c>
996 </a>''')
997
998 pi = tree.getroot().getprevious()
999 self.assertEqual("TEST", pi.get("href"))
1000 self.assertEqual("text/xsl", pi.get("type"))
1001 self.assertEqual(None, pi.get("motz"))
1002
1004 tree = self.parse('''\
1005 <?xml version="1.0"?>
1006 <?xml-stylesheet href="TEST" type="text/xsl"?>
1007 <a>
1008 <b>B</b>
1009 <c>C</c>
1010 </a>''')
1011
1012 pi = tree.getroot().getprevious()
1013 self.assertEqual("TEST", pi.get("href"))
1014 self.assertEqual("text/xsl", pi.get("type"))
1015 self.assertEqual(None, pi.get("motz"))
1016
1018 tree = self.parse('''\
1019 <?xml version="1.0"?>
1020 <?xml-stylesheet type="text/xsl" href="TEST"?>
1021 <a>
1022 <b>B</b>
1023 <c>C</c>
1024 </a>''')
1025
1026 pi = tree.getroot().getprevious()
1027 self.assertEqual(None, pi.get("unknownattribute"))
1028
1030 tree = self.parse('''\
1031 <?xml version="1.0"?>
1032 <?xml-stylesheet type="text/xsl" href="TEST"?>
1033 <a>
1034 <b>B</b>
1035 <c>C</c>
1036 </a>''')
1037
1038 pi = tree.getroot().getprevious()
1039 self.assertEqual("TEST", pi.get("href"))
1040
1041 pi.set("href", "TEST123")
1042 self.assertEqual("TEST123", pi.get("href"))
1043
1045 tree = self.parse('''\
1046 <?xml version="1.0"?>
1047 <?xml-stylesheet type="text/xsl"?>
1048 <a>
1049 <b>B</b>
1050 <c>C</c>
1051 </a>''')
1052
1053 pi = tree.getroot().getprevious()
1054 self.assertEqual(None, pi.get("href"))
1055
1056 pi.set("href", "TEST")
1057 self.assertEqual("TEST", pi.get("href"))
1058
1060 """EXSLT tests"""
1061
1063 tree = self.parse('<a><b>B</b><c>C</c></a>')
1064 style = self.parse('''\
1065 <xsl:stylesheet version="1.0"
1066 xmlns:str="http://exslt.org/strings"
1067 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1068 exclude-result-prefixes="str xsl">
1069 <xsl:template match="text()">
1070 <xsl:value-of select="str:align(string(.), '***', 'center')" />
1071 </xsl:template>
1072 <xsl:template match="*">
1073 <xsl:copy>
1074 <xsl:apply-templates/>
1075 </xsl:copy>
1076 </xsl:template>
1077 </xsl:stylesheet>''')
1078
1079 st = etree.XSLT(style)
1080 res = st(tree)
1081 self.assertEqual('''\
1082 <?xml version="1.0"?>
1083 <a><b>*B*</b><c>*C*</c></a>
1084 ''',
1085 str(res))
1086
1088 tree = self.parse('<a><b>B</b><c>C</c></a>')
1089 style = self.parse('''\
1090 <xsl:stylesheet version = "1.0"
1091 xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
1092 xmlns:str="http://exslt.org/strings"
1093 extension-element-prefixes="str">
1094
1095 <xsl:template match="/">
1096 <h1 class="{str:replace('abc', 'b', 'x')}">test</h1>
1097 </xsl:template>
1098
1099 </xsl:stylesheet>''')
1100
1101 st = etree.XSLT(style)
1102 res = st(tree)
1103 self.assertEqual(str(res), '''\
1104 <?xml version="1.0"?>
1105 <h1 class="axc">test</h1>
1106 ''')
1107
1109 tree = self.parse('<a><b>B</b><c>C</c></a>')
1110 style = self.parse('''\
1111 <xsl:stylesheet version="1.0"
1112 xmlns:math="http://exslt.org/math"
1113 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1114 exclude-result-prefixes="math xsl">
1115 <xsl:template match="*">
1116 <xsl:copy>
1117 <xsl:attribute name="pi">
1118 <xsl:value-of select="math:constant('PI', count(*)+2)"/>
1119 </xsl:attribute>
1120 <xsl:apply-templates/>
1121 </xsl:copy>
1122 </xsl:template>
1123 </xsl:stylesheet>''')
1124
1125 st = etree.XSLT(style)
1126 res = st(tree)
1127 self.assertEqual('''\
1128 <?xml version="1.0"?>
1129 <a pi="3.14"><b pi="3">B</b><c pi="3">C</c></a>
1130 ''',
1131 str(res))
1132
1134 xslt = etree.XSLT(etree.XML(_bytes("""\
1135 <xsl:stylesheet version="1.0"
1136 xmlns:regexp="http://exslt.org/regular-expressions"
1137 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1138 <xsl:template match="*">
1139 <test><xsl:copy-of select="*[regexp:test(string(.), '8.')]"/></test>
1140 </xsl:template>
1141 </xsl:stylesheet>
1142 """)))
1143 result = xslt(etree.XML(_bytes('<a><b>123</b><b>098</b><b>987</b></a>')))
1144 root = result.getroot()
1145 self.assertEqual(root.tag,
1146 'test')
1147 self.assertEqual(len(root), 1)
1148 self.assertEqual(root[0].tag,
1149 'b')
1150 self.assertEqual(root[0].text,
1151 '987')
1152
1154 xslt = etree.XSLT(etree.XML("""\
1155 <xsl:stylesheet version="1.0"
1156 xmlns:regexp="http://exslt.org/regular-expressions"
1157 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1158 <xsl:template match="*">
1159 <test>
1160 <xsl:copy-of select="regexp:replace(string(.), 'd.', '', 'XX')"/>
1161 <xsl:text>-</xsl:text>
1162 <xsl:copy-of select="regexp:replace(string(.), 'd.', 'gi', 'XX')"/>
1163 </test>
1164 </xsl:template>
1165 </xsl:stylesheet>
1166 """))
1167 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1168 root = result.getroot()
1169 self.assertEqual(root.tag,
1170 'test')
1171 self.assertEqual(len(root), 0)
1172 self.assertEqual(root.text, 'abXXdEeDed-abXXXXeXXd')
1173
1175 xslt = etree.XSLT(etree.XML("""\
1176 <xsl:stylesheet version="1.0"
1177 xmlns:regexp="http://exslt.org/regular-expressions"
1178 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1179 <xsl:template match="*">
1180 <test>
1181 <test1><xsl:copy-of select="regexp:match(string(.), 'd.')"/></test1>
1182 <test2><xsl:copy-of select="regexp:match(string(.), 'd.', 'g')"/></test2>
1183 <test2i><xsl:copy-of select="regexp:match(string(.), 'd.', 'gi')"/></test2i>
1184 </test>
1185 </xsl:template>
1186 </xsl:stylesheet>
1187 """))
1188 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1189 root = result.getroot()
1190 self.assertEqual(root.tag, 'test')
1191 self.assertEqual(len(root), 3)
1192
1193 self.assertEqual(len(root[0]), 1)
1194 self.assertEqual(root[0][0].tag, 'match')
1195 self.assertEqual(root[0][0].text, 'dC')
1196
1197 self.assertEqual(len(root[1]), 2)
1198 self.assertEqual(root[1][0].tag, 'match')
1199 self.assertEqual(root[1][0].text, 'dC')
1200 self.assertEqual(root[1][1].tag, 'match')
1201 self.assertEqual(root[1][1].text, 'dE')
1202
1203 self.assertEqual(len(root[2]), 3)
1204 self.assertEqual(root[2][0].tag, 'match')
1205 self.assertEqual(root[2][0].text, 'dC')
1206 self.assertEqual(root[2][1].tag, 'match')
1207 self.assertEqual(root[2][1].text, 'dE')
1208 self.assertEqual(root[2][2].tag, 'match')
1209 self.assertEqual(root[2][2].text, 'De')
1210
1212 xslt = etree.XSLT(etree.XML(_bytes("""\
1213 <xsl:stylesheet version="1.0"
1214 xmlns:regexp="http://exslt.org/regular-expressions"
1215 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1216 <xsl:template match="/">
1217 <test>
1218 <xsl:for-each select="regexp:match(
1219 '123abc567', '([0-9]+)([a-z]+)([0-9]+)' )">
1220 <test1><xsl:value-of select="."/></test1>
1221 </xsl:for-each>
1222 </test>
1223 </xsl:template>
1224 </xsl:stylesheet>
1225 """)))
1226 result = xslt(etree.XML(_bytes('<a/>')))
1227 root = result.getroot()
1228 self.assertEqual(root.tag, 'test')
1229 self.assertEqual(len(root), 4)
1230
1231 self.assertEqual(root[0].text, "123abc567")
1232 self.assertEqual(root[1].text, "123")
1233 self.assertEqual(root[2].text, "abc")
1234 self.assertEqual(root[3].text, "567")
1235
1237
1238 xslt = etree.XSLT(etree.XML(_bytes("""\
1239 <xsl:stylesheet version="1.0"
1240 xmlns:regexp="http://exslt.org/regular-expressions"
1241 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1242 <xsl:template match="/">
1243 <test>
1244 <xsl:for-each select="regexp:match(
1245 'http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml',
1246 '(\\w+):\\/\\/([^/:]+)(:\\d*)?([^# ]*)')">
1247 <test1><xsl:value-of select="."/></test1>
1248 </xsl:for-each>
1249 </test>
1250 </xsl:template>
1251 </xsl:stylesheet>
1252 """)))
1253 result = xslt(etree.XML(_bytes('<a/>')))
1254 root = result.getroot()
1255 self.assertEqual(root.tag, 'test')
1256 self.assertEqual(len(root), 5)
1257
1258 self.assertEqual(
1259 root[0].text,
1260 "http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml")
1261 self.assertEqual(
1262 root[1].text,
1263 "http")
1264 self.assertEqual(
1265 root[2].text,
1266 "www.bayes.co.uk")
1267 self.assertFalse(root[3].text)
1268 self.assertEqual(
1269 root[4].text,
1270 "/xml/index.xml?/xml/utils/rechecker.xml")
1271
1273
1274 xslt = etree.XSLT(self.parse("""\
1275 <xsl:stylesheet version="1.0"
1276 xmlns:regexp="http://exslt.org/regular-expressions"
1277 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1278 <xsl:template match="/">
1279 <test>
1280 <xsl:for-each select="regexp:match(
1281 'This is a test string', '(\\w+)', 'g')">
1282 <test1><xsl:value-of select="."/></test1>
1283 </xsl:for-each>
1284 </test>
1285 </xsl:template>
1286 </xsl:stylesheet>
1287 """))
1288 result = xslt(etree.XML(_bytes('<a/>')))
1289 root = result.getroot()
1290 self.assertEqual(root.tag, 'test')
1291 self.assertEqual(len(root), 5)
1292
1293 self.assertEqual(root[0].text, "This")
1294 self.assertEqual(root[1].text, "is")
1295 self.assertEqual(root[2].text, "a")
1296 self.assertEqual(root[3].text, "test")
1297 self.assertEqual(root[4].text, "string")
1298
1300
1301
1302 xslt = etree.XSLT(etree.XML(_bytes("""\
1303 <xsl:stylesheet version="1.0"
1304 xmlns:regexp="http://exslt.org/regular-expressions"
1305 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1306 <xsl:template match="/">
1307 <test>
1308 <xsl:for-each select="regexp:match(
1309 'This is a test string', '([a-z])+ ', 'g')">
1310 <test1><xsl:value-of select="."/></test1>
1311 </xsl:for-each>
1312 </test>
1313 </xsl:template>
1314 </xsl:stylesheet>
1315 """)))
1316 result = xslt(etree.XML(_bytes('<a/>')))
1317 root = result.getroot()
1318 self.assertEqual(root.tag, 'test')
1319 self.assertEqual(len(root), 4)
1320
1321 self.assertEqual(root[0].text, "his")
1322 self.assertEqual(root[1].text, "is")
1323 self.assertEqual(root[2].text, "a")
1324 self.assertEqual(root[3].text, "test")
1325
1327
1328
1329 xslt = etree.XSLT(etree.XML(_bytes("""\
1330 <xsl:stylesheet version="1.0"
1331 xmlns:regexp="http://exslt.org/regular-expressions"
1332 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1333 <xsl:template match="/">
1334 <test>
1335 <xsl:for-each select="regexp:match(
1336 'This is a test string', '([a-z])+ ', 'gi')">
1337 <test1><xsl:value-of select="."/></test1>
1338 </xsl:for-each>
1339 </test>
1340 </xsl:template>
1341 </xsl:stylesheet>
1342 """)))
1343 result = xslt(etree.XML(_bytes('<a/>')))
1344 root = result.getroot()
1345 self.assertEqual(root.tag, 'test')
1346 self.assertEqual(len(root), 4)
1347
1348 self.assertEqual(root[0].text, "This")
1349 self.assertEqual(root[1].text, "is")
1350 self.assertEqual(root[2].text, "a")
1351 self.assertEqual(root[3].text, "test")
1352
1353
1354 -class ETreeXSLTExtFuncTestCase(HelperTestCase):
1355 """Tests for XPath extension functions in XSLT."""
1356
1357 - def test_extensions1(self):
1358 tree = self.parse('<a><b>B</b></a>')
1359 style = self.parse('''\
1360 <xsl:stylesheet version="1.0"
1361 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1362 xmlns:myns="testns"
1363 exclude-result-prefixes="myns">
1364 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
1365 </xsl:stylesheet>''')
1366
1367 def mytext(ctxt, values):
1368 return 'X' * len(values)
1369
1370 result = tree.xslt(style, {('testns', 'mytext') : mytext})
1371 self.assertEqual(self._rootstring(result),
1372 _bytes('<A>X</A>'))
1373
1374 - def test_extensions2(self):
1375 tree = self.parse('<a><b>B</b></a>')
1376 style = self.parse('''\
1377 <xsl:stylesheet version="1.0"
1378 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1379 xmlns:myns="testns"
1380 exclude-result-prefixes="myns">
1381 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
1382 </xsl:stylesheet>''')
1383
1384 def mytext(ctxt, values):
1385 return 'X' * len(values)
1386
1387 namespace = etree.FunctionNamespace('testns')
1388 namespace['mytext'] = mytext
1389
1390 result = tree.xslt(style)
1391 self.assertEqual(self._rootstring(result),
1392 _bytes('<A>X</A>'))
1393
1395 tree = self.parse('<a><b>B</b><b/></a>')
1396 style = self.parse('''\
1397 <xsl:stylesheet version="1.0"
1398 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1399 xmlns:myns="testns"
1400 exclude-result-prefixes="myns">
1401 <xsl:template match="a">
1402 <xsl:variable name="content">
1403 <xsl:apply-templates/>
1404 </xsl:variable>
1405 <A><xsl:value-of select="myns:mytext($content)"/></A>
1406 </xsl:template>
1407 <xsl:template match="b"><xsl:copy>BBB</xsl:copy></xsl:template>
1408 </xsl:stylesheet>''')
1409
1410 def mytext(ctxt, values):
1411 for value in values:
1412 self.assertTrue(hasattr(value, 'tag'),
1413 "%s is not an Element" % type(value))
1414 self.assertEqual(value.tag, 'b')
1415 self.assertEqual(value.text, 'BBB')
1416 return 'X'.join([el.tag for el in values])
1417
1418 namespace = etree.FunctionNamespace('testns')
1419 namespace['mytext'] = mytext
1420
1421 result = tree.xslt(style)
1422 self.assertEqual(self._rootstring(result),
1423 _bytes('<A>bXb</A>'))
1424
1426 tree = self.parse('<a><b>B<c/>C</b><b/></a>')
1427 style = self.parse('''\
1428 <xsl:stylesheet version="1.0"
1429 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1430 xmlns:myns="testns"
1431 exclude-result-prefixes="myns">
1432 <xsl:template match="b">
1433 <A><xsl:value-of select="myns:myext()"/></A>
1434 </xsl:template>
1435 </xsl:stylesheet>''')
1436
1437 def extfunc(ctxt):
1438 text_content = ctxt.context_node.xpath('text()')
1439 return 'x'.join(text_content)
1440
1441 namespace = etree.FunctionNamespace('testns')
1442 namespace['myext'] = extfunc
1443
1444 result = tree.xslt(style)
1445 self.assertEqual(self._rootstring(result),
1446 _bytes('<A>BxC</A>'))
1447
1449
1450 class Resolver(etree.Resolver):
1451 def resolve(self, system_url, public_id, context):
1452 assert system_url == 'extdoc.xml'
1453 return self.resolve_string(b'<a><b>B<c/>C</b><b/></a>', context)
1454
1455 parser = etree.XMLParser()
1456 parser.resolvers.add(Resolver())
1457
1458 tree = self.parse(b'<a><b/><b/></a>')
1459 transform = etree.XSLT(self.parse(b'''\
1460 <xsl:stylesheet version="1.0"
1461 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1462 xmlns:mypre="testns"
1463 exclude-result-prefixes="mypre">
1464 <xsl:template match="b">
1465 <B><xsl:value-of select="mypre:myext()"/></B>
1466 </xsl:template>
1467 <xsl:template match="a">
1468 <A><xsl:apply-templates select="document('extdoc.xml')//b" /></A>
1469 </xsl:template>
1470 </xsl:stylesheet>''', parser=parser))
1471
1472 def extfunc(ctxt):
1473 text_content = ctxt.context_node.xpath('text()')
1474 return 'x'.join(text_content)
1475
1476 namespace = etree.FunctionNamespace('testns')
1477 namespace['myext'] = extfunc
1478
1479 result = transform(tree)
1480 self.assertEqual(self._rootstring(result),
1481 _bytes('<A><B>BxC</B><B/></A>'))
1482
1483
1484 -class ETreeXSLTExtElementTestCase(HelperTestCase):
1485 """Tests for extension elements in XSLT."""
1486
1488 tree = self.parse('<a><b>B</b></a>')
1489 style = self.parse('''\
1490 <xsl:stylesheet version="1.0"
1491 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1492 xmlns:myns="testns"
1493 extension-element-prefixes="myns"
1494 exclude-result-prefixes="myns">
1495 <xsl:template match="a">
1496 <A><myns:myext>b</myns:myext></A>
1497 </xsl:template>
1498 </xsl:stylesheet>''')
1499
1500 class MyExt(etree.XSLTExtension):
1501 def execute(self, context, self_node, input_node, output_parent):
1502 child = etree.Element(self_node.text)
1503 child.text = 'X'
1504 output_parent.append(child)
1505
1506 extensions = { ('testns', 'myext') : MyExt() }
1507
1508 result = tree.xslt(style, extensions=extensions)
1509 self.assertEqual(self._rootstring(result),
1510 _bytes('<A><b>X</b></A>'))
1511
1513 tree = self.parse('<a><b>B</b></a>')
1514 style = self.parse('''\
1515 <xsl:stylesheet version="1.0"
1516 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1517 xmlns:myns="testns"
1518 extension-element-prefixes="myns"
1519 exclude-result-prefixes="myns">
1520 <xsl:template match="/">
1521 <A><myns:myext>b</myns:myext></A>
1522 </xsl:template>
1523 </xsl:stylesheet>''')
1524
1525 tags = []
1526
1527 class MyExt(etree.XSLTExtension):
1528 def execute(self, context, self_node, input_node, output_parent):
1529 tags.append(input_node.tag)
1530
1531 extensions = { ('testns', 'myext') : MyExt() }
1532
1533 result = tree.xslt(style, extensions=extensions)
1534 self.assertEqual(tags, ['a'])
1535
1537 tree = self.parse('<?test toast?><a><!--a comment--><?another pi?></a>')
1538 style = self.parse('''\
1539 <xsl:stylesheet version="1.0"
1540 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1541 xmlns:myns="testns"
1542 extension-element-prefixes="myns"
1543 exclude-result-prefixes="myns">
1544 <xsl:template match="/">
1545 <ROOT><xsl:apply-templates /></ROOT>
1546 </xsl:template>
1547 <xsl:template match="comment()">
1548 <A><myns:myext>b</myns:myext></A>
1549 </xsl:template>
1550 <xsl:template match="processing-instruction()">
1551 <A><myns:myext>b</myns:myext></A>
1552 </xsl:template>
1553 </xsl:stylesheet>''')
1554
1555 text = []
1556
1557 class MyExt(etree.XSLTExtension):
1558 def execute(self, context, self_node, input_node, output_parent):
1559 text.append(input_node.text)
1560
1561 extensions = { ('testns', 'myext') : MyExt() }
1562
1563 result = tree.xslt(style, extensions=extensions)
1564 self.assertEqual(text, ['toast', 'a comment', 'pi'])
1565
1567
1568 tree = self.parse('<a test="A"><b attr="B"/></a>')
1569 style = self.parse('''\
1570 <xsl:stylesheet version="1.0"
1571 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1572 xmlns:myns="testns"
1573 extension-element-prefixes="myns"
1574 exclude-result-prefixes="myns">
1575 <xsl:template match="@test">
1576 <A><myns:myext>b</myns:myext></A>
1577 </xsl:template>
1578 <xsl:template match="@attr">
1579 <A><myns:myext>b</myns:myext></A>
1580 </xsl:template>
1581 </xsl:stylesheet>''')
1582
1583 text = []
1584
1585 class MyExt(etree.XSLTExtension):
1586 def execute(self, context, self_node, attr_value, output_parent):
1587 text.append(attr_value)
1588
1589 extensions = { ('testns', 'myext') : MyExt() }
1590
1591 result = tree.xslt(style, extensions=extensions)
1592 self.assertEqual(text, ['A', 'B'])
1593
1595 tree = self.parse('<a><b>B</b></a>')
1596 style = self.parse('''\
1597 <xsl:stylesheet version="1.0"
1598 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1599 xmlns:myns="testns"
1600 extension-element-prefixes="myns">
1601 <xsl:template match="a">
1602 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1603 </xsl:template>
1604 </xsl:stylesheet>''')
1605
1606 class MyExt(etree.XSLTExtension):
1607 def execute(self, context, self_node, input_node, output_parent):
1608 output_parent.extend(list(self_node)[1:])
1609
1610 extensions = { ('testns', 'myext') : MyExt() }
1611
1612 result = tree.xslt(style, extensions=extensions)
1613 self.assertEqual(self._rootstring(result),
1614 _bytes('<A><y>Y</y><z/></A>'))
1615
1617 tree = self.parse('<a><b>B</b></a>')
1618 style = self.parse('''\
1619 <xsl:stylesheet version="1.0"
1620 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1621 xmlns:myns="testns"
1622 extension-element-prefixes="myns">
1623 <xsl:template match="a">
1624 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1625 </xsl:template>
1626 <xsl:template match="x" />
1627 <xsl:template match="z">XYZ</xsl:template>
1628 </xsl:stylesheet>''')
1629
1630 class MyExt(etree.XSLTExtension):
1631 def execute(self, context, self_node, input_node, output_parent):
1632 for child in self_node:
1633 for result in self.apply_templates(context, child):
1634 if isinstance(result, basestring):
1635 el = etree.Element("T")
1636 el.text = result
1637 else:
1638 el = result
1639 output_parent.append(el)
1640
1641 extensions = { ('testns', 'myext') : MyExt() }
1642
1643 result = tree.xslt(style, extensions=extensions)
1644 self.assertEqual(self._rootstring(result),
1645 _bytes('<A><T>Y</T><T>XYZ</T></A>'))
1646
1648 tree = self.parse('<a><b>B</b></a>')
1649 style = self.parse('''\
1650 <xsl:stylesheet version="1.0"
1651 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1652 xmlns:myns="testns"
1653 extension-element-prefixes="myns">
1654 <xsl:template match="a">
1655 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1656 </xsl:template>
1657 <xsl:template match="x"><X/></xsl:template>
1658 <xsl:template match="z">XYZ</xsl:template>
1659 </xsl:stylesheet>''')
1660
1661 class MyExt(etree.XSLTExtension):
1662 def execute(self, context, self_node, input_node, output_parent):
1663 for child in self_node:
1664 for result in self.apply_templates(context, child,
1665 elements_only=True):
1666 assert not isinstance(result, basestring)
1667 output_parent.append(result)
1668
1669 extensions = { ('testns', 'myext') : MyExt() }
1670
1671 result = tree.xslt(style, extensions=extensions)
1672 self.assertEqual(self._rootstring(result),
1673 _bytes('<A><X/></A>'))
1674
1676 tree = self.parse('<a><b>B</b></a>')
1677 style = self.parse('''\
1678 <xsl:stylesheet version="1.0"
1679 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1680 xmlns:myns="testns"
1681 extension-element-prefixes="myns">
1682 <xsl:template match="a">
1683 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1684 </xsl:template>
1685 <xsl:template match="x"><X/></xsl:template>
1686 <xsl:template match="y"><xsl:text> </xsl:text></xsl:template>
1687 <xsl:template match="z">XYZ</xsl:template>
1688 </xsl:stylesheet>''')
1689
1690 class MyExt(etree.XSLTExtension):
1691 def execute(self, context, self_node, input_node, output_parent):
1692 for child in self_node:
1693 for result in self.apply_templates(context, child,
1694 remove_blank_text=True):
1695 if isinstance(result, basestring):
1696 assert result.strip()
1697 el = etree.Element("T")
1698 el.text = result
1699 else:
1700 el = result
1701 output_parent.append(el)
1702
1703 extensions = { ('testns', 'myext') : MyExt() }
1704
1705 result = tree.xslt(style, extensions=extensions)
1706 self.assertEqual(self._rootstring(result),
1707 _bytes('<A><X/><T>XYZ</T></A>'))
1708
1710 tree = self.parse('<a><b>B</b></a>')
1711 style = self.parse('''\
1712 <xsl:stylesheet version="1.0"
1713 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1714 xmlns:myns="testns"
1715 extension-element-prefixes="myns">
1716 <xsl:template match="a">
1717 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1718 </xsl:template>
1719 <xsl:template match="x" />
1720 <xsl:template match="z">XYZ</xsl:template>
1721 </xsl:stylesheet>''')
1722
1723 class MyExt(etree.XSLTExtension):
1724 def execute(self, context, self_node, input_node, output_parent):
1725 for child in self_node:
1726 self.apply_templates(context, child, output_parent)
1727
1728 extensions = { ('testns', 'myext') : MyExt() }
1729
1730 result = tree.xslt(style, extensions=extensions)
1731 self.assertEqual(self._rootstring(result),
1732 _bytes('<A>YXYZ</A>'))
1733
1735 tree = self.parse('<a><b>B</b></a>')
1736 style = self.parse('''\
1737 <xsl:stylesheet version="1.0"
1738 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1739 xmlns:myns="testns"
1740 extension-element-prefixes="myns">
1741 <xsl:template match="a">
1742 <myns:myext><x>X</x><y>Y</y><z/></myns:myext>
1743 </xsl:template>
1744 <xsl:template match="x"><xsl:processing-instruction name="test">TEST</xsl:processing-instruction></xsl:template>
1745 <xsl:template match="y"><Y>XYZ</Y></xsl:template>
1746 <xsl:template match="z"><xsl:comment>TEST</xsl:comment></xsl:template>
1747 </xsl:stylesheet>''')
1748
1749 class MyExt(etree.XSLTExtension):
1750 def execute(self, context, self_node, input_node, output_parent):
1751 for child in self_node:
1752 self.apply_templates(context, child, output_parent)
1753
1754 extensions = { ('testns', 'myext') : MyExt() }
1755
1756 result = tree.xslt(style, extensions=extensions)
1757 self.assertEqual(etree.tostring(result),
1758 _bytes('<?test TEST?><Y>XYZ</Y><!--TEST-->'))
1759
1761 tree = self.parse('<a><b>E</b></a>')
1762 style = self.parse('''\
1763 <xsl:stylesheet version="1.0"
1764 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1765 xmlns:myns="testns"
1766 extension-element-prefixes="myns">
1767 <xsl:template match="a">
1768 <xsl:variable name="testvar">yo</xsl:variable>
1769 <A>
1770 <myns:myext>
1771 <xsl:attribute name="attr">
1772 <xsl:value-of select="$testvar" />
1773 </xsl:attribute>
1774 <B>
1775 <xsl:choose>
1776 <xsl:when test="1 = 2"><C/></xsl:when>
1777 <xsl:otherwise><D><xsl:value-of select="b/text()" /></D></xsl:otherwise>
1778 </xsl:choose>
1779 </B>
1780 </myns:myext>
1781 </A>
1782 </xsl:template>
1783 </xsl:stylesheet>''')
1784
1785 class MyExt(etree.XSLTExtension):
1786 def execute(self, context, self_node, input_node, output_parent):
1787 el = etree.Element('MY')
1788 self.process_children(context, el)
1789 output_parent.append(el)
1790
1791 extensions = { ('testns', 'myext') : MyExt() }
1792
1793 result = tree.xslt(style, extensions=extensions)
1794 self.assertEqual(self._rootstring(result),
1795 _bytes('<A><MYattr="yo"><B><D>E</D></B></MY></A>'))
1796
1798 tree = self.parse('<a/>')
1799 style = self.parse('''\
1800 <xsl:stylesheet version="1.0"
1801 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1802 xmlns:myns="testns"
1803 extension-element-prefixes="myns">
1804 <xsl:template match="a">
1805 <myns:myext>
1806 <A/>
1807 </myns:myext>
1808 </xsl:template>
1809 </xsl:stylesheet>''')
1810
1811 class MyExt(etree.XSLTExtension):
1812 def execute(self, context, self_node, input_node, output_parent):
1813 self.process_children(context, output_parent)
1814
1815 extensions = { ('testns', 'myext') : MyExt() }
1816
1817 result = tree.xslt(style, extensions=extensions)
1818 self.assertEqual(self._rootstring(result),
1819 _bytes('<A/>'))
1820
1822 tree = self.parse('<a/>')
1823 style = self.parse('''\
1824 <xsl:stylesheet version="1.0"
1825 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1826 xmlns:myns="testns"
1827 extension-element-prefixes="myns">
1828 <xsl:template match="a">
1829 <myns:myext>
1830 <A/>
1831 </myns:myext>
1832 </xsl:template>
1833 </xsl:stylesheet>''')
1834
1835 class MyExt(etree.XSLTExtension):
1836 def execute(self, context, self_node, input_node, output_parent):
1837 self.process_children(context, self_node)
1838
1839 extensions = { ('testns', 'myext') : MyExt() }
1840
1841 self.assertRaises(TypeError, tree.xslt, style, extensions=extensions)
1842
1844 tree = self.parse('<a/>')
1845 style = self.parse('''\
1846 <xsl:stylesheet version="1.0"
1847 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1848 xmlns:myns="testns"
1849 extension-element-prefixes="myns">
1850 <xsl:template match="a">
1851 <myns:myext>
1852 <A><myns:myext><B/></myns:myext></A>
1853 </myns:myext>
1854 </xsl:template>
1855 </xsl:stylesheet>''')
1856
1857 class MyExt(etree.XSLTExtension):
1858 callback_call_counter = 0
1859 def execute(self, context, self_node, input_node, output_parent):
1860 self.callback_call_counter += 1
1861 el = etree.Element('MY', n=str(self.callback_call_counter))
1862 self.process_children(context, el)
1863 output_parent.append(el)
1864
1865 extensions = { ('testns', 'myext') : MyExt() }
1866
1867 result = tree.xslt(style, extensions=extensions)
1868 self.assertEqual(self._rootstring(result),
1869 _bytes('<MYn="1"><A><MYn="2"><B/></MY></A></MY>'))
1870
1872 tree = self.parse('<a><b>B</b></a>')
1873 style = self.parse('''\
1874 <xsl:stylesheet version="1.0"
1875 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1876 xmlns:myns="testns"
1877 extension-element-prefixes="myns"
1878 exclude-result-prefixes="myns">
1879 <xsl:template match="a">
1880 <A><myns:myext>b</myns:myext></A>
1881 </xsl:template>
1882 </xsl:stylesheet>''')
1883
1884 class MyError(Exception):
1885 pass
1886
1887 class MyExt(etree.XSLTExtension):
1888 def execute(self, context, self_node, input_node, output_parent):
1889 raise MyError("expected!")
1890
1891 extensions = { ('testns', 'myext') : MyExt() }
1892 self.assertRaises(MyError, tree.xslt, style, extensions=extensions)
1893
1894
1895
1897 tree = self.parse("""\
1898 <text>
1899 <par>This is <format>arbitrary</format> text in a paragraph</par>
1900 </text>""")
1901 style = self.parse("""\
1902 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my" extension-element-prefixes="my" version="1.0">
1903 <xsl:template match="par">
1904 <my:par><xsl:apply-templates /></my:par>
1905 </xsl:template>
1906 <xsl:template match="format">
1907 <my:format><xsl:apply-templates /></my:format>
1908 </xsl:template>
1909 </xsl:stylesheet>
1910 """)
1911 test = self
1912 calls = []
1913
1914 class ExtMyPar(etree.XSLTExtension):
1915 def execute(self, context, self_node, input_node, output_parent):
1916 calls.append('par')
1917 p = etree.Element("p")
1918 p.attrib["style"] = "color:red"
1919 self.process_children(context, p)
1920 output_parent.append(p)
1921
1922 class ExtMyFormat(etree.XSLTExtension):
1923 def execute(self, context, self_node, input_node, output_parent):
1924 calls.append('format')
1925 content = self.process_children(context)
1926 test.assertEqual(1, len(content))
1927 test.assertEqual('arbitrary', content[0])
1928 test.assertEqual('This is ', output_parent.text)
1929 output_parent.text += '*-%s-*' % content[0]
1930
1931 extensions = {("my", "par"): ExtMyPar(), ("my", "format"): ExtMyFormat()}
1932 transform = etree.XSLT(style, extensions=extensions)
1933 result = transform(tree)
1934 self.assertEqual(['par', 'format'], calls)
1935 self.assertEqual(
1936 b'<p style="color:red">This is *-arbitrary-* text in a paragraph</p>\n',
1937 etree.tostring(result))
1938
1941 """XSLT tests for etree under Python 3"""
1942
1943 pytestmark = skipif('sys.version_info < (3,0)')
1944
1946 tree = self.parse('<a><b>B</b><c>C</c></a>')
1947 style = self.parse('''\
1948 <xsl:stylesheet version="1.0"
1949 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1950 <xsl:template match="*" />
1951 <xsl:template match="/">
1952 <foo><xsl:value-of select="/a/b/text()" /></foo>
1953 </xsl:template>
1954 </xsl:stylesheet>''')
1955
1956 st = etree.XSLT(style)
1957 res = st(tree)
1958 self.assertEqual(_bytes('''\
1959 <?xml version="1.0"?>
1960 <foo>B</foo>
1961 '''),
1962 bytes(res))
1963
1965 tree = self.parse('<a><b>B</b><c>C</c></a>')
1966 style = self.parse('''\
1967 <xsl:stylesheet version="1.0"
1968 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1969 <xsl:template match="*" />
1970 <xsl:template match="/">
1971 <foo><xsl:value-of select="/a/b/text()" /></foo>
1972 </xsl:template>
1973 </xsl:stylesheet>''')
1974
1975 st = etree.XSLT(style)
1976 res = st(tree)
1977 self.assertEqual(_bytes('''\
1978 <?xml version="1.0"?>
1979 <foo>B</foo>
1980 '''),
1981 bytearray(res))
1982
1984 tree = self.parse('<a><b>B</b><c>C</c></a>')
1985 style = self.parse('''\
1986 <xsl:stylesheet version="1.0"
1987 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1988 <xsl:template match="*" />
1989 <xsl:template match="/">
1990 <foo><xsl:value-of select="/a/b/text()" /></foo>
1991 </xsl:template>
1992 </xsl:stylesheet>''')
1993
1994 st = etree.XSLT(style)
1995 res = st(tree)
1996 self.assertEqual(_bytes('''\
1997 <?xml version="1.0"?>
1998 <foo>B</foo>
1999 '''),
2000 bytes(memoryview(res)))
2001
2016
2017 if __name__ == '__main__':
2018 print('to test use test.py %s' % __file__)
2019