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(tree)
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><b>B</b><c>C</c></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="/">
294 <foo><xsl:value-of select="$bar" /></foo>
295 </xsl:template>
296 </xsl:stylesheet>''')
297
298 st = etree.XSLT(style)
299 res = st(tree, bar="'Bar'")
300 self.assertEqual('''\
301 <?xml version="1.0"?>
302 <foo>Bar</foo>
303 ''',
304 str(res))
305
307 tree = self.parse('<a><b>B</b><c>C</c></a>')
308 style = self.parse('''\
309 <xsl:stylesheet version="1.0"
310 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
311 <xsl:template match="/">
312 <foo><xsl:value-of select="$bar" /></foo>
313 </xsl:template>
314 </xsl:stylesheet>''')
315
316 st = etree.XSLT(style)
317 res = st(tree, bar=etree.XSLT.strparam('''it's me, "Bar"'''))
318 self.assertEqual('''\
319 <?xml version="1.0"?>
320 <foo>it's me, "Bar"</foo>
321 ''',
322 str(res))
323
325 tree = self.parse('<a><b>B</b><c>C</c></a>')
326 style = self.parse('''\
327 <xsl:stylesheet version="1.0"
328 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
329 <xsl:param name="bar"/>
330 <xsl:template match="/">
331 <foo><xsl:value-of select="$bar" /></foo>
332 </xsl:template>
333 </xsl:stylesheet>''')
334
335 st = etree.XSLT(style)
336 res = self.assertRaises(etree.XSLTApplyError,
337 st, tree, bar="<test/>")
338 res = self.assertRaises(etree.XSLTApplyError,
339 st, tree, bar="....")
340
342
343 tree = self.parse('<a><b>B</b><c>C</c></a>')
344 style = self.parse('''\
345 <xsl:stylesheet version="1.0"
346 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
347 <xsl:template match="/">
348 <foo><xsl:value-of select="$bar" /></foo>
349 </xsl:template>
350 </xsl:stylesheet>''')
351
352 st = etree.XSLT(style)
353
354 self.assertRaises(etree.XSLTApplyError, st.apply, tree)
355
357 tree = self.parse('<a><b>B</b><c>C</c></a>')
358 style = self.parse('''\
359 <xsl:stylesheet version="1.0"
360 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
361 <xsl:template match="*" />
362 <xsl:template match="/">
363 <foo><xsl:value-of select="$bar" /></foo>
364 <foo><xsl:value-of select="$baz" /></foo>
365 </xsl:template>
366 </xsl:stylesheet>''')
367
368 st = etree.XSLT(style)
369 res = st(tree, bar="'Bar'", baz="'Baz'")
370 self.assertEqual('''\
371 <?xml version="1.0"?>
372 <foo>Bar</foo><foo>Baz</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 <xsl:template match="/">
383 <foo><xsl:value-of select="$bar" /></foo>
384 </xsl:template>
385 </xsl:stylesheet>''')
386
387 st = etree.XSLT(style)
388 res = st(tree, bar="/a/b/text()")
389 self.assertEqual('''\
390 <?xml version="1.0"?>
391 <foo>B</foo>
392 ''',
393 str(res))
394
396 tree = self.parse('<a><b>B</b><c>C</c></a>')
397 style = self.parse('''\
398 <xsl:stylesheet version="1.0"
399 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
400 <xsl:template match="*" />
401 <xsl:template match="/">
402 <foo><xsl:value-of select="$bar" /></foo>
403 </xsl:template>
404 </xsl:stylesheet>''')
405
406 st = etree.XSLT(style)
407 res = st(tree, bar=etree.XPath("/a/b/text()"))
408 self.assertEqual('''\
409 <?xml version="1.0"?>
410 <foo>B</foo>
411 ''',
412 str(res))
413
415 tree = self.parse('<a><b>B</b><c>C</c></a>')
416 style = self.parse('''\
417 <xsl:stylesheet version="1.0"
418 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
419 <xsl:param name="bar" select="'Default'" />
420 <xsl:template match="*" />
421 <xsl:template match="/">
422 <foo><xsl:value-of select="$bar" /></foo>
423 </xsl:template>
424 </xsl:stylesheet>''')
425
426 st = etree.XSLT(style)
427 res = st(tree, bar="'Bar'")
428 self.assertEqual('''\
429 <?xml version="1.0"?>
430 <foo>Bar</foo>
431 ''',
432 str(res))
433 res = st(tree)
434 self.assertEqual('''\
435 <?xml version="1.0"?>
436 <foo>Default</foo>
437 ''',
438 str(res))
439
441 tree = self.parse('<a><b>B</b><c>C</c></a>')
442 style = self.parse('''\
443 <xsl:stylesheet version="1.0"
444 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
445 <xsl:output method="html"/>
446 <xsl:strip-space elements="*"/>
447 <xsl:template match="/">
448 <html><body><xsl:value-of select="/a/b/text()" /></body></html>
449 </xsl:template>
450 </xsl:stylesheet>''')
451
452 st = etree.XSLT(style)
453 res = st(tree)
454 self.assertEqual('<html><body>B</body></html>',
455 str(res).strip())
456
460
466
489
514
516
517 xml = '<blah/>'
518 xslt = '''
519 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
520 <xsl:template match="/" />
521 </xsl:stylesheet>
522 '''
523
524 source = self.parse(xml)
525 styledoc = self.parse(xslt)
526 style = etree.XSLT(styledoc)
527 result = style(source)
528 self.assertEqual('', str(result))
529
531 xml = '<blah/>'
532 xslt = '''
533 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
534 <xsl:template match="/">
535 <xsl:message>TEST TEST TEST</xsl:message>
536 </xsl:template>
537 </xsl:stylesheet>
538 '''
539
540 source = self.parse(xml)
541 styledoc = self.parse(xslt)
542 style = etree.XSLT(styledoc)
543 result = style(source)
544 self.assertEqual('', str(result))
545 self.assertTrue("TEST TEST TEST" in [entry.message
546 for entry in style.error_log])
547
549 xml = '<blah/>'
550 xslt = '''
551 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
552 <xsl:template match="/">
553 <xsl:message terminate="yes">TEST TEST TEST</xsl:message>
554 </xsl:template>
555 </xsl:stylesheet>
556 '''
557
558 source = self.parse(xml)
559 styledoc = self.parse(xslt)
560 style = etree.XSLT(styledoc)
561
562 self.assertRaises(etree.XSLTApplyError, style, source)
563 self.assertTrue("TEST TEST TEST" in [entry.message
564 for entry in style.error_log])
565
567 tree = self.parse('<a><b>B</b><c>C</c></a>')
568 style = self.parse('''\
569 <xsl:stylesheet version="1.0"
570 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
571 <xsl:template match="*" />
572 <xsl:template match="/">
573 <doc>
574 <foo><xsl:value-of select="$bar" /></foo>
575 <foo><xsl:value-of select="$baz" /></foo>
576 </doc>
577 </xsl:template>
578 </xsl:stylesheet>''')
579
580 result = tree.xslt(style, bar="'Bar'", baz="'Baz'")
581 self.assertEqual(
582 _bytes('<doc><foo>Bar</foo><foo>Baz</foo></doc>'),
583 etree.tostring(result.getroot()))
584
586 tree = self.parse('<a><b>B</b><c>C</c></a>')
587 style = self.parse('''\
588 <xsl:stylesheet version="1.0"
589 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
590 <xsl:template match="a"><A><xsl:apply-templates/></A></xsl:template>
591 <xsl:template match="b"><B><xsl:apply-templates/></B></xsl:template>
592 <xsl:template match="c"><C><xsl:apply-templates/></C></xsl:template>
593 </xsl:stylesheet>''')
594
595 self.assertEqual(self._rootstring(tree),
596 _bytes('<a><b>B</b><c>C</c></a>'))
597 result = tree.xslt(style)
598 self.assertEqual(self._rootstring(tree),
599 _bytes('<a><b>B</b><c>C</c></a>'))
600 self.assertEqual(self._rootstring(result),
601 _bytes('<A><B>B</B><C>C</C></A>'))
602
603 b_tree = etree.ElementTree(tree.getroot()[0])
604 self.assertEqual(self._rootstring(b_tree),
605 _bytes('<b>B</b>'))
606 result = b_tree.xslt(style)
607 self.assertEqual(self._rootstring(tree),
608 _bytes('<a><b>B</b><c>C</c></a>'))
609 self.assertEqual(self._rootstring(result),
610 _bytes('<B>B</B>'))
611
612 c_tree = etree.ElementTree(tree.getroot()[1])
613 self.assertEqual(self._rootstring(c_tree),
614 _bytes('<c>C</c>'))
615 result = c_tree.xslt(style)
616 self.assertEqual(self._rootstring(tree),
617 _bytes('<a><b>B</b><c>C</c></a>'))
618 self.assertEqual(self._rootstring(result),
619 _bytes('<C>C</C>'))
620
622
623 xslt = etree.XSLT(etree.XML("""\
624 <xsl:stylesheet version="1.0"
625 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
626 <xsl:template match="/">
627 <test>TEXT<xsl:copy-of select="document('')//test"/></test>
628 </xsl:template>
629 </xsl:stylesheet>
630 """))
631 result = xslt(etree.XML('<a/>'))
632 root = result.getroot()
633 self.assertEqual(root.tag,
634 'test')
635 self.assertEqual(root[0].tag,
636 'test')
637 self.assertEqual(root[0].text,
638 'TEXT')
639 self.assertEqual(root[0][0].tag,
640 '{http://www.w3.org/1999/XSL/Transform}copy-of')
641
651
661
663 xslt = etree.XSLT(etree.XML("""\
664 <xsl:stylesheet version="1.0"
665 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
666 <xsl:template match="/">
667 <test>TEXT<xsl:copy-of select="document('uri:__junkfood__is__evil__')//test"/></test>
668 </xsl:template>
669 </xsl:stylesheet>
670 """))
671
672 errors = None
673 try:
674 xslt(etree.XML('<a/>'))
675 except etree.XSLTApplyError as exc:
676 errors = exc.error_log
677 else:
678 self.assertFalse(True, "XSLT processing should have failed but didn't")
679
680 self.assertTrue(len(errors))
681 for error in errors:
682 if ':ERROR:XSLT:' in str(error):
683 break
684 else:
685 self.assertFalse(True, 'No XSLT errors found in error log:\n%s' % errors)
686
688
689 assertEqual = self.assertEqual
690 called = {'count' : 0}
691 class TestResolver(etree.Resolver):
692 def resolve(self, url, id, context):
693 assertEqual(url, 'file://ANYTHING')
694 called['count'] += 1
695 return self.resolve_string('<CALLED/>', context)
696
697 parser = etree.XMLParser()
698 parser.resolvers.add(TestResolver())
699
700 xslt = etree.XSLT(etree.XML(_bytes("""\
701 <xsl:stylesheet version="1.0"
702 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
703 xmlns:l="local">
704 <xsl:template match="/">
705 <test>
706 <xsl:for-each select="document('')//l:data/l:entry">
707 <xsl:copy-of select="document('file://ANYTHING')"/>
708 <xsl:copy>
709 <xsl:attribute name="value">
710 <xsl:value-of select="."/>
711 </xsl:attribute>
712 </xsl:copy>
713 </xsl:for-each>
714 </test>
715 </xsl:template>
716 <l:data>
717 <l:entry>A</l:entry>
718 <l:entry>B</l:entry>
719 </l:data>
720 </xsl:stylesheet>
721 """), parser))
722
723 self.assertEqual(called['count'], 0)
724 result = xslt(etree.XML('<a/>'))
725 self.assertEqual(called['count'], 1)
726
727 root = result.getroot()
728 self.assertEqual(root.tag,
729 'test')
730 self.assertEqual(len(root), 4)
731
732 self.assertEqual(root[0].tag,
733 'CALLED')
734 self.assertEqual(root[1].tag,
735 '{local}entry')
736 self.assertEqual(root[1].text,
737 None)
738 self.assertEqual(root[1].get("value"),
739 'A')
740 self.assertEqual(root[2].tag,
741 'CALLED')
742 self.assertEqual(root[3].tag,
743 '{local}entry')
744 self.assertEqual(root[3].text,
745 None)
746 self.assertEqual(root[3].get("value"),
747 'B')
748
750 assertEqual = self.assertEqual
751 called = {'count' : 0}
752 expected_url = None
753 class TestResolver(etree.Resolver):
754 def resolve(self, url, id, context):
755 assertEqual(url, expected_url)
756 called['count'] += 1
757 return self.resolve_string('<CALLED/>', context)
758
759 stylesheet_xml = _bytes("""\
760 <xsl:stylesheet version="1.0"
761 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
762 xmlns:l="local">
763 <xsl:template match="/">
764 <xsl:copy-of select="document('test.xml')"/>
765 </xsl:template>
766 </xsl:stylesheet>
767 """)
768
769 parser = etree.XMLParser()
770 parser.resolvers.add(TestResolver())
771
772
773 expected_url = 'test.xml'
774 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser))
775
776 self.assertEqual(called['count'], 0)
777 result = xslt(etree.XML('<a/>'))
778 self.assertEqual(called['count'], 1)
779
780
781 called['count'] = 0
782 expected_url = 'MY/BASE/test.xml'
783 xslt = etree.XSLT(etree.XML(
784 stylesheet_xml, parser,
785 base_url=os.path.join('MY', 'BASE', 'FILE')))
786
787 self.assertEqual(called['count'], 0)
788 result = xslt(etree.XML('<a/>'))
789 self.assertEqual(called['count'], 1)
790
791
792 called['count'] = 0
793 expected_url = 'http://server.com/BASE/DIR/test.xml'
794 xslt = etree.XSLT(etree.XML(
795 stylesheet_xml, parser,
796 base_url='http://server.com/BASE/DIR/FILE'))
797
798 self.assertEqual(called['count'], 0)
799 result = xslt(etree.XML('<a/>'))
800 self.assertEqual(called['count'], 1)
801
802
803 called['count'] = 0
804 expected_url = 'file://BASE/DIR/test.xml'
805 xslt = etree.XSLT(etree.XML(
806 stylesheet_xml, parser,
807 base_url='file://BASE/DIR/FILE'))
808
809 self.assertEqual(called['count'], 0)
810 result = xslt(etree.XML('<a/>'))
811 self.assertEqual(called['count'], 1)
812
823
829
835
844
846 root = etree.XML(_bytes('''\
847 <transform>
848 <widget displayType="fieldset"/>
849 </transform>'''))
850
851 xslt = etree.XSLT(etree.XML(_bytes('''\
852 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
853 <xsl:output method="html" indent="no"/>
854 <xsl:template match="/">
855 <html>
856 <xsl:apply-templates/>
857 </html>
858 </xsl:template>
859
860 <xsl:template match="widget">
861 <xsl:element name="{@displayType}"/>
862 </xsl:template>
863
864 </xsl:stylesheet>''')))
865
866 result = xslt(root[0])
867 root[:] = result.getroot()[:]
868 del root
869
871 tree = self.parse('''\
872 <?xml version="1.0"?>
873 <?xml-stylesheet type="text/xsl" href="%s"?>
874 <a>
875 <b>B</b>
876 <c>C</c>
877 </a>''' % fileInTestDir("test1.xslt"))
878
879 style_root = tree.getroot().getprevious().parseXSL().getroot()
880 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
881 style_root.tag)
882
884
885 tree = self.parse('''\
886 <?xml version="1.0"?>
887 <?xml-stylesheet type="text/xsl" href="#style"?>
888 <a>
889 <b>B</b>
890 <c>C</c>
891 <xsl:stylesheet version="1.0" xml:id="style"
892 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
893 <xsl:template match="*" />
894 <xsl:template match="/">
895 <foo><xsl:value-of select="/a/b/text()" /></foo>
896 </xsl:template>
897 </xsl:stylesheet>
898 </a>''')
899
900 style_root = tree.getroot().getprevious().parseXSL().getroot()
901 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
902 style_root.tag)
903
904 st = etree.XSLT(style_root)
905 res = st(tree)
906 self.assertEqual('''\
907 <?xml version="1.0"?>
908 <foo>B</foo>
909 ''',
910 str(res))
911
913
914 tree = self.parse('''\
915 <?xml version="1.0"?>
916 <?xml-stylesheet type="text/xsl" href="#style"?>
917 <a>
918 <b>B</b>
919 <c>C</c>
920 </a>''')
921
922 style = self.parse('''\
923 <xsl:stylesheet version="1.0" xml:id="style"
924 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
925 <xsl:template match="*" />
926 <xsl:template match="/">
927 <foo><xsl:value-of select="/a/b/text()" /></foo>
928 </xsl:template>
929 </xsl:stylesheet>
930 ''')
931
932 tree.getroot().append(style.getroot())
933
934 style_root = tree.getroot().getprevious().parseXSL().getroot()
935 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
936 style_root.tag)
937
938 st = etree.XSLT(style_root)
939 res = st(tree)
940 self.assertEqual('''\
941 <?xml version="1.0"?>
942 <foo>B</foo>
943 ''',
944 str(res))
945
947 tree = self.parse('''\
948 <?xml version="1.0"?>
949 <?xml-stylesheet type="text/xsl" href="TEST"?>
950 <a>
951 <b>B</b>
952 <c>C</c>
953 </a>''')
954
955 pi = tree.getroot().getprevious()
956 self.assertEqual("TEST", pi.get("href"))
957
959 tree = self.parse('''\
960 <?xml version="1.0"?>
961 <?xml-stylesheet type="text/xsl" href="TEST"?>
962 <a>
963 <b>B</b>
964 <c>C</c>
965 </a>''')
966
967 pi = tree.getroot().getprevious()
968 self.assertEqual("TEST", pi.get("href"))
969 self.assertEqual("text/xsl", pi.get("type"))
970 self.assertEqual(None, pi.get("motz"))
971
973 tree = self.parse('''\
974 <?xml version="1.0"?>
975 <?xml-stylesheet href="TEST" type="text/xsl"?>
976 <a>
977 <b>B</b>
978 <c>C</c>
979 </a>''')
980
981 pi = tree.getroot().getprevious()
982 self.assertEqual("TEST", pi.get("href"))
983 self.assertEqual("text/xsl", pi.get("type"))
984 self.assertEqual(None, pi.get("motz"))
985
987 tree = self.parse('''\
988 <?xml version="1.0"?>
989 <?xml-stylesheet type="text/xsl" href="TEST"?>
990 <a>
991 <b>B</b>
992 <c>C</c>
993 </a>''')
994
995 pi = tree.getroot().getprevious()
996 self.assertEqual(None, pi.get("unknownattribute"))
997
999 tree = self.parse('''\
1000 <?xml version="1.0"?>
1001 <?xml-stylesheet type="text/xsl" href="TEST"?>
1002 <a>
1003 <b>B</b>
1004 <c>C</c>
1005 </a>''')
1006
1007 pi = tree.getroot().getprevious()
1008 self.assertEqual("TEST", pi.get("href"))
1009
1010 pi.set("href", "TEST123")
1011 self.assertEqual("TEST123", pi.get("href"))
1012
1014 tree = self.parse('''\
1015 <?xml version="1.0"?>
1016 <?xml-stylesheet type="text/xsl"?>
1017 <a>
1018 <b>B</b>
1019 <c>C</c>
1020 </a>''')
1021
1022 pi = tree.getroot().getprevious()
1023 self.assertEqual(None, pi.get("href"))
1024
1025 pi.set("href", "TEST")
1026 self.assertEqual("TEST", pi.get("href"))
1027
1029 """EXSLT tests"""
1030
1032 tree = self.parse('<a><b>B</b><c>C</c></a>')
1033 style = self.parse('''\
1034 <xsl:stylesheet version="1.0"
1035 xmlns:str="http://exslt.org/strings"
1036 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1037 exclude-result-prefixes="str xsl">
1038 <xsl:template match="text()">
1039 <xsl:value-of select="str:align(string(.), '***', 'center')" />
1040 </xsl:template>
1041 <xsl:template match="*">
1042 <xsl:copy>
1043 <xsl:apply-templates/>
1044 </xsl:copy>
1045 </xsl:template>
1046 </xsl:stylesheet>''')
1047
1048 st = etree.XSLT(style)
1049 res = st(tree)
1050 self.assertEqual('''\
1051 <?xml version="1.0"?>
1052 <a><b>*B*</b><c>*C*</c></a>
1053 ''',
1054 str(res))
1055
1057 tree = self.parse('<a><b>B</b><c>C</c></a>')
1058 style = self.parse('''\
1059 <xsl:stylesheet version = "1.0"
1060 xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
1061 xmlns:str="http://exslt.org/strings"
1062 extension-element-prefixes="str">
1063
1064 <xsl:template match="/">
1065 <h1 class="{str:replace('abc', 'b', 'x')}">test</h1>
1066 </xsl:template>
1067
1068 </xsl:stylesheet>''')
1069
1070 st = etree.XSLT(style)
1071 res = st(tree)
1072 self.assertEqual(str(res), '''\
1073 <?xml version="1.0"?>
1074 <h1 class="axc">test</h1>
1075 ''')
1076
1078 tree = self.parse('<a><b>B</b><c>C</c></a>')
1079 style = self.parse('''\
1080 <xsl:stylesheet version="1.0"
1081 xmlns:math="http://exslt.org/math"
1082 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1083 exclude-result-prefixes="math xsl">
1084 <xsl:template match="*">
1085 <xsl:copy>
1086 <xsl:attribute name="pi">
1087 <xsl:value-of select="math:constant('PI', count(*)+2)"/>
1088 </xsl:attribute>
1089 <xsl:apply-templates/>
1090 </xsl:copy>
1091 </xsl:template>
1092 </xsl:stylesheet>''')
1093
1094 st = etree.XSLT(style)
1095 res = st(tree)
1096 self.assertEqual('''\
1097 <?xml version="1.0"?>
1098 <a pi="3.14"><b pi="3">B</b><c pi="3">C</c></a>
1099 ''',
1100 str(res))
1101
1103 xslt = etree.XSLT(etree.XML(_bytes("""\
1104 <xsl:stylesheet version="1.0"
1105 xmlns:regexp="http://exslt.org/regular-expressions"
1106 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1107 <xsl:template match="*">
1108 <test><xsl:copy-of select="*[regexp:test(string(.), '8.')]"/></test>
1109 </xsl:template>
1110 </xsl:stylesheet>
1111 """)))
1112 result = xslt(etree.XML(_bytes('<a><b>123</b><b>098</b><b>987</b></a>')))
1113 root = result.getroot()
1114 self.assertEqual(root.tag,
1115 'test')
1116 self.assertEqual(len(root), 1)
1117 self.assertEqual(root[0].tag,
1118 'b')
1119 self.assertEqual(root[0].text,
1120 '987')
1121
1123 xslt = etree.XSLT(etree.XML("""\
1124 <xsl:stylesheet version="1.0"
1125 xmlns:regexp="http://exslt.org/regular-expressions"
1126 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1127 <xsl:template match="*">
1128 <test>
1129 <xsl:copy-of select="regexp:replace(string(.), 'd.', '', 'XX')"/>
1130 <xsl:text>-</xsl:text>
1131 <xsl:copy-of select="regexp:replace(string(.), 'd.', 'gi', 'XX')"/>
1132 </test>
1133 </xsl:template>
1134 </xsl:stylesheet>
1135 """))
1136 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1137 root = result.getroot()
1138 self.assertEqual(root.tag,
1139 'test')
1140 self.assertEqual(len(root), 0)
1141 self.assertEqual(root.text, 'abXXdEeDed-abXXXXeXXd')
1142
1144 xslt = etree.XSLT(etree.XML("""\
1145 <xsl:stylesheet version="1.0"
1146 xmlns:regexp="http://exslt.org/regular-expressions"
1147 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1148 <xsl:template match="*">
1149 <test>
1150 <test1><xsl:copy-of select="regexp:match(string(.), 'd.')"/></test1>
1151 <test2><xsl:copy-of select="regexp:match(string(.), 'd.', 'g')"/></test2>
1152 <test2i><xsl:copy-of select="regexp:match(string(.), 'd.', 'gi')"/></test2i>
1153 </test>
1154 </xsl:template>
1155 </xsl:stylesheet>
1156 """))
1157 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1158 root = result.getroot()
1159 self.assertEqual(root.tag, 'test')
1160 self.assertEqual(len(root), 3)
1161
1162 self.assertEqual(len(root[0]), 1)
1163 self.assertEqual(root[0][0].tag, 'match')
1164 self.assertEqual(root[0][0].text, 'dC')
1165
1166 self.assertEqual(len(root[1]), 2)
1167 self.assertEqual(root[1][0].tag, 'match')
1168 self.assertEqual(root[1][0].text, 'dC')
1169 self.assertEqual(root[1][1].tag, 'match')
1170 self.assertEqual(root[1][1].text, 'dE')
1171
1172 self.assertEqual(len(root[2]), 3)
1173 self.assertEqual(root[2][0].tag, 'match')
1174 self.assertEqual(root[2][0].text, 'dC')
1175 self.assertEqual(root[2][1].tag, 'match')
1176 self.assertEqual(root[2][1].text, 'dE')
1177 self.assertEqual(root[2][2].tag, 'match')
1178 self.assertEqual(root[2][2].text, 'De')
1179
1181 xslt = etree.XSLT(etree.XML(_bytes("""\
1182 <xsl:stylesheet version="1.0"
1183 xmlns:regexp="http://exslt.org/regular-expressions"
1184 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1185 <xsl:template match="/">
1186 <test>
1187 <xsl:for-each select="regexp:match(
1188 '123abc567', '([0-9]+)([a-z]+)([0-9]+)' )">
1189 <test1><xsl:value-of select="."/></test1>
1190 </xsl:for-each>
1191 </test>
1192 </xsl:template>
1193 </xsl:stylesheet>
1194 """)))
1195 result = xslt(etree.XML(_bytes('<a/>')))
1196 root = result.getroot()
1197 self.assertEqual(root.tag, 'test')
1198 self.assertEqual(len(root), 4)
1199
1200 self.assertEqual(root[0].text, "123abc567")
1201 self.assertEqual(root[1].text, "123")
1202 self.assertEqual(root[2].text, "abc")
1203 self.assertEqual(root[3].text, "567")
1204
1206
1207 xslt = etree.XSLT(etree.XML(_bytes("""\
1208 <xsl:stylesheet version="1.0"
1209 xmlns:regexp="http://exslt.org/regular-expressions"
1210 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1211 <xsl:template match="/">
1212 <test>
1213 <xsl:for-each select="regexp:match(
1214 'http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml',
1215 '(\\w+):\\/\\/([^/:]+)(:\\d*)?([^# ]*)')">
1216 <test1><xsl:value-of select="."/></test1>
1217 </xsl:for-each>
1218 </test>
1219 </xsl:template>
1220 </xsl:stylesheet>
1221 """)))
1222 result = xslt(etree.XML(_bytes('<a/>')))
1223 root = result.getroot()
1224 self.assertEqual(root.tag, 'test')
1225 self.assertEqual(len(root), 5)
1226
1227 self.assertEqual(
1228 root[0].text,
1229 "http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml")
1230 self.assertEqual(
1231 root[1].text,
1232 "http")
1233 self.assertEqual(
1234 root[2].text,
1235 "www.bayes.co.uk")
1236 self.assertFalse(root[3].text)
1237 self.assertEqual(
1238 root[4].text,
1239 "/xml/index.xml?/xml/utils/rechecker.xml")
1240
1242
1243 xslt = etree.XSLT(self.parse("""\
1244 <xsl:stylesheet version="1.0"
1245 xmlns:regexp="http://exslt.org/regular-expressions"
1246 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1247 <xsl:template match="/">
1248 <test>
1249 <xsl:for-each select="regexp:match(
1250 'This is a test string', '(\\w+)', 'g')">
1251 <test1><xsl:value-of select="."/></test1>
1252 </xsl:for-each>
1253 </test>
1254 </xsl:template>
1255 </xsl:stylesheet>
1256 """))
1257 result = xslt(etree.XML(_bytes('<a/>')))
1258 root = result.getroot()
1259 self.assertEqual(root.tag, 'test')
1260 self.assertEqual(len(root), 5)
1261
1262 self.assertEqual(root[0].text, "This")
1263 self.assertEqual(root[1].text, "is")
1264 self.assertEqual(root[2].text, "a")
1265 self.assertEqual(root[3].text, "test")
1266 self.assertEqual(root[4].text, "string")
1267
1269
1270
1271 xslt = etree.XSLT(etree.XML(_bytes("""\
1272 <xsl:stylesheet version="1.0"
1273 xmlns:regexp="http://exslt.org/regular-expressions"
1274 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1275 <xsl:template match="/">
1276 <test>
1277 <xsl:for-each select="regexp:match(
1278 'This is a test string', '([a-z])+ ', 'g')">
1279 <test1><xsl:value-of select="."/></test1>
1280 </xsl:for-each>
1281 </test>
1282 </xsl:template>
1283 </xsl:stylesheet>
1284 """)))
1285 result = xslt(etree.XML(_bytes('<a/>')))
1286 root = result.getroot()
1287 self.assertEqual(root.tag, 'test')
1288 self.assertEqual(len(root), 4)
1289
1290 self.assertEqual(root[0].text, "his")
1291 self.assertEqual(root[1].text, "is")
1292 self.assertEqual(root[2].text, "a")
1293 self.assertEqual(root[3].text, "test")
1294
1296
1297
1298 xslt = etree.XSLT(etree.XML(_bytes("""\
1299 <xsl:stylesheet version="1.0"
1300 xmlns:regexp="http://exslt.org/regular-expressions"
1301 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1302 <xsl:template match="/">
1303 <test>
1304 <xsl:for-each select="regexp:match(
1305 'This is a test string', '([a-z])+ ', 'gi')">
1306 <test1><xsl:value-of select="."/></test1>
1307 </xsl:for-each>
1308 </test>
1309 </xsl:template>
1310 </xsl:stylesheet>
1311 """)))
1312 result = xslt(etree.XML(_bytes('<a/>')))
1313 root = result.getroot()
1314 self.assertEqual(root.tag, 'test')
1315 self.assertEqual(len(root), 4)
1316
1317 self.assertEqual(root[0].text, "This")
1318 self.assertEqual(root[1].text, "is")
1319 self.assertEqual(root[2].text, "a")
1320 self.assertEqual(root[3].text, "test")
1321
1322
1323 -class ETreeXSLTExtFuncTestCase(HelperTestCase):
1324 """Tests for XPath extension functions in XSLT."""
1325
1326 - def test_extensions1(self):
1327 tree = self.parse('<a><b>B</b></a>')
1328 style = self.parse('''\
1329 <xsl:stylesheet version="1.0"
1330 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1331 xmlns:myns="testns"
1332 exclude-result-prefixes="myns">
1333 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
1334 </xsl:stylesheet>''')
1335
1336 def mytext(ctxt, values):
1337 return 'X' * len(values)
1338
1339 result = tree.xslt(style, {('testns', 'mytext') : mytext})
1340 self.assertEqual(self._rootstring(result),
1341 _bytes('<A>X</A>'))
1342
1343 - def test_extensions2(self):
1344 tree = self.parse('<a><b>B</b></a>')
1345 style = self.parse('''\
1346 <xsl:stylesheet version="1.0"
1347 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1348 xmlns:myns="testns"
1349 exclude-result-prefixes="myns">
1350 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
1351 </xsl:stylesheet>''')
1352
1353 def mytext(ctxt, values):
1354 return 'X' * len(values)
1355
1356 namespace = etree.FunctionNamespace('testns')
1357 namespace['mytext'] = mytext
1358
1359 result = tree.xslt(style)
1360 self.assertEqual(self._rootstring(result),
1361 _bytes('<A>X</A>'))
1362
1364 tree = self.parse('<a><b>B</b><b/></a>')
1365 style = self.parse('''\
1366 <xsl:stylesheet version="1.0"
1367 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1368 xmlns:myns="testns"
1369 exclude-result-prefixes="myns">
1370 <xsl:template match="a">
1371 <xsl:variable name="content">
1372 <xsl:apply-templates/>
1373 </xsl:variable>
1374 <A><xsl:value-of select="myns:mytext($content)"/></A>
1375 </xsl:template>
1376 <xsl:template match="b"><xsl:copy>BBB</xsl:copy></xsl:template>
1377 </xsl:stylesheet>''')
1378
1379 def mytext(ctxt, values):
1380 for value in values:
1381 self.assertTrue(hasattr(value, 'tag'),
1382 "%s is not an Element" % type(value))
1383 self.assertEqual(value.tag, 'b')
1384 self.assertEqual(value.text, 'BBB')
1385 return 'X'.join([el.tag for el in 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>bXb</A>'))
1393
1395 tree = self.parse('<a><b>B<c/>C</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="b">
1402 <A><xsl:value-of select="myns:myext()"/></A>
1403 </xsl:template>
1404 </xsl:stylesheet>''')
1405
1406 def extfunc(ctxt):
1407 text_content = ctxt.context_node.xpath('text()')
1408 return 'x'.join(text_content)
1409
1410 namespace = etree.FunctionNamespace('testns')
1411 namespace['myext'] = extfunc
1412
1413 result = tree.xslt(style)
1414 self.assertEqual(self._rootstring(result),
1415 _bytes('<A>BxC</A>'))
1416
1418
1419 class Resolver(etree.Resolver):
1420 def resolve(self, system_url, public_id, context):
1421 assert system_url == 'extdoc.xml'
1422 return self.resolve_string(b'<a><b>B<c/>C</b><b/></a>', context)
1423
1424 parser = etree.XMLParser()
1425 parser.resolvers.add(Resolver())
1426
1427 tree = self.parse(b'<a><b/><b/></a>')
1428 transform = etree.XSLT(self.parse(b'''\
1429 <xsl:stylesheet version="1.0"
1430 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1431 xmlns:mypre="testns"
1432 exclude-result-prefixes="mypre">
1433 <xsl:template match="b">
1434 <B><xsl:value-of select="mypre:myext()"/></B>
1435 </xsl:template>
1436 <xsl:template match="a">
1437 <A><xsl:apply-templates select="document('extdoc.xml')//b" /></A>
1438 </xsl:template>
1439 </xsl:stylesheet>''', parser=parser))
1440
1441 def extfunc(ctxt):
1442 text_content = ctxt.context_node.xpath('text()')
1443 return 'x'.join(text_content)
1444
1445 namespace = etree.FunctionNamespace('testns')
1446 namespace['myext'] = extfunc
1447
1448 result = transform(tree)
1449 self.assertEqual(self._rootstring(result),
1450 _bytes('<A><B>BxC</B><B/></A>'))
1451
1452
1453 -class ETreeXSLTExtElementTestCase(HelperTestCase):
1454 """Tests for extension elements in XSLT."""
1455
1457 tree = self.parse('<a><b>B</b></a>')
1458 style = self.parse('''\
1459 <xsl:stylesheet version="1.0"
1460 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1461 xmlns:myns="testns"
1462 extension-element-prefixes="myns"
1463 exclude-result-prefixes="myns">
1464 <xsl:template match="a">
1465 <A><myns:myext>b</myns:myext></A>
1466 </xsl:template>
1467 </xsl:stylesheet>''')
1468
1469 class MyExt(etree.XSLTExtension):
1470 def execute(self, context, self_node, input_node, output_parent):
1471 child = etree.Element(self_node.text)
1472 child.text = 'X'
1473 output_parent.append(child)
1474
1475 extensions = { ('testns', 'myext') : MyExt() }
1476
1477 result = tree.xslt(style, extensions=extensions)
1478 self.assertEqual(self._rootstring(result),
1479 _bytes('<A><b>X</b></A>'))
1480
1482 tree = self.parse('<a><b>B</b></a>')
1483 style = self.parse('''\
1484 <xsl:stylesheet version="1.0"
1485 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1486 xmlns:myns="testns"
1487 extension-element-prefixes="myns"
1488 exclude-result-prefixes="myns">
1489 <xsl:template match="/">
1490 <A><myns:myext>b</myns:myext></A>
1491 </xsl:template>
1492 </xsl:stylesheet>''')
1493
1494 tags = []
1495
1496 class MyExt(etree.XSLTExtension):
1497 def execute(self, context, self_node, input_node, output_parent):
1498 tags.append(input_node.tag)
1499
1500 extensions = { ('testns', 'myext') : MyExt() }
1501
1502 result = tree.xslt(style, extensions=extensions)
1503 self.assertEqual(tags, ['a'])
1504
1506 tree = self.parse('<?test toast?><a><!--a comment--><?another pi?></a>')
1507 style = self.parse('''\
1508 <xsl:stylesheet version="1.0"
1509 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1510 xmlns:myns="testns"
1511 extension-element-prefixes="myns"
1512 exclude-result-prefixes="myns">
1513 <xsl:template match="/">
1514 <ROOT><xsl:apply-templates /></ROOT>
1515 </xsl:template>
1516 <xsl:template match="comment()">
1517 <A><myns:myext>b</myns:myext></A>
1518 </xsl:template>
1519 <xsl:template match="processing-instruction()">
1520 <A><myns:myext>b</myns:myext></A>
1521 </xsl:template>
1522 </xsl:stylesheet>''')
1523
1524 text = []
1525
1526 class MyExt(etree.XSLTExtension):
1527 def execute(self, context, self_node, input_node, output_parent):
1528 text.append(input_node.text)
1529
1530 extensions = { ('testns', 'myext') : MyExt() }
1531
1532 result = tree.xslt(style, extensions=extensions)
1533 self.assertEqual(text, ['toast', 'a comment', 'pi'])
1534
1536
1537 tree = self.parse('<a test="A"><b attr="B"/></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="@test">
1545 <A><myns:myext>b</myns:myext></A>
1546 </xsl:template>
1547 <xsl:template match="@attr">
1548 <A><myns:myext>b</myns:myext></A>
1549 </xsl:template>
1550 </xsl:stylesheet>''')
1551
1552 text = []
1553
1554 class MyExt(etree.XSLTExtension):
1555 def execute(self, context, self_node, attr_value, output_parent):
1556 text.append(attr_value)
1557
1558 extensions = { ('testns', 'myext') : MyExt() }
1559
1560 result = tree.xslt(style, extensions=extensions)
1561 self.assertEqual(text, ['A', 'B'])
1562
1564 tree = self.parse('<a><b>B</b></a>')
1565 style = self.parse('''\
1566 <xsl:stylesheet version="1.0"
1567 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1568 xmlns:myns="testns"
1569 extension-element-prefixes="myns">
1570 <xsl:template match="a">
1571 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1572 </xsl:template>
1573 </xsl:stylesheet>''')
1574
1575 class MyExt(etree.XSLTExtension):
1576 def execute(self, context, self_node, input_node, output_parent):
1577 output_parent.extend(list(self_node)[1:])
1578
1579 extensions = { ('testns', 'myext') : MyExt() }
1580
1581 result = tree.xslt(style, extensions=extensions)
1582 self.assertEqual(self._rootstring(result),
1583 _bytes('<A><y>Y</y><z/></A>'))
1584
1586 tree = self.parse('<a><b>B</b></a>')
1587 style = self.parse('''\
1588 <xsl:stylesheet version="1.0"
1589 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1590 xmlns:myns="testns"
1591 extension-element-prefixes="myns">
1592 <xsl:template match="a">
1593 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1594 </xsl:template>
1595 <xsl:template match="x" />
1596 <xsl:template match="z">XYZ</xsl:template>
1597 </xsl:stylesheet>''')
1598
1599 class MyExt(etree.XSLTExtension):
1600 def execute(self, context, self_node, input_node, output_parent):
1601 for child in self_node:
1602 for result in self.apply_templates(context, child):
1603 if isinstance(result, basestring):
1604 el = etree.Element("T")
1605 el.text = result
1606 else:
1607 el = result
1608 output_parent.append(el)
1609
1610 extensions = { ('testns', 'myext') : MyExt() }
1611
1612 result = tree.xslt(style, extensions=extensions)
1613 self.assertEqual(self._rootstring(result),
1614 _bytes('<A><T>Y</T><T>XYZ</T></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"><X/></xsl:template>
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 elements_only=True):
1635 assert not isinstance(result, basestring)
1636 output_parent.append(result)
1637
1638 extensions = { ('testns', 'myext') : MyExt() }
1639
1640 result = tree.xslt(style, extensions=extensions)
1641 self.assertEqual(self._rootstring(result),
1642 _bytes('<A><X/></A>'))
1643
1645 tree = self.parse('<a><b>B</b></a>')
1646 style = self.parse('''\
1647 <xsl:stylesheet version="1.0"
1648 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1649 xmlns:myns="testns"
1650 extension-element-prefixes="myns">
1651 <xsl:template match="a">
1652 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1653 </xsl:template>
1654 <xsl:template match="x"><X/></xsl:template>
1655 <xsl:template match="y"><xsl:text> </xsl:text></xsl:template>
1656 <xsl:template match="z">XYZ</xsl:template>
1657 </xsl:stylesheet>''')
1658
1659 class MyExt(etree.XSLTExtension):
1660 def execute(self, context, self_node, input_node, output_parent):
1661 for child in self_node:
1662 for result in self.apply_templates(context, child,
1663 remove_blank_text=True):
1664 if isinstance(result, basestring):
1665 assert result.strip()
1666 el = etree.Element("T")
1667 el.text = result
1668 else:
1669 el = result
1670 output_parent.append(el)
1671
1672 extensions = { ('testns', 'myext') : MyExt() }
1673
1674 result = tree.xslt(style, extensions=extensions)
1675 self.assertEqual(self._rootstring(result),
1676 _bytes('<A><X/><T>XYZ</T></A>'))
1677
1679 tree = self.parse('<a><b>B</b></a>')
1680 style = self.parse('''\
1681 <xsl:stylesheet version="1.0"
1682 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1683 xmlns:myns="testns"
1684 extension-element-prefixes="myns">
1685 <xsl:template match="a">
1686 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1687 </xsl:template>
1688 <xsl:template match="x" />
1689 <xsl:template match="z">XYZ</xsl:template>
1690 </xsl:stylesheet>''')
1691
1692 class MyExt(etree.XSLTExtension):
1693 def execute(self, context, self_node, input_node, output_parent):
1694 for child in self_node:
1695 self.apply_templates(context, child, output_parent)
1696
1697 extensions = { ('testns', 'myext') : MyExt() }
1698
1699 result = tree.xslt(style, extensions=extensions)
1700 self.assertEqual(self._rootstring(result),
1701 _bytes('<A>YXYZ</A>'))
1702
1704 tree = self.parse('<a><b>B</b></a>')
1705 style = self.parse('''\
1706 <xsl:stylesheet version="1.0"
1707 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1708 xmlns:myns="testns"
1709 extension-element-prefixes="myns">
1710 <xsl:template match="a">
1711 <myns:myext><x>X</x><y>Y</y><z/></myns:myext>
1712 </xsl:template>
1713 <xsl:template match="x"><xsl:processing-instruction name="test">TEST</xsl:processing-instruction></xsl:template>
1714 <xsl:template match="y"><Y>XYZ</Y></xsl:template>
1715 <xsl:template match="z"><xsl:comment>TEST</xsl:comment></xsl:template>
1716 </xsl:stylesheet>''')
1717
1718 class MyExt(etree.XSLTExtension):
1719 def execute(self, context, self_node, input_node, output_parent):
1720 for child in self_node:
1721 self.apply_templates(context, child, output_parent)
1722
1723 extensions = { ('testns', 'myext') : MyExt() }
1724
1725 result = tree.xslt(style, extensions=extensions)
1726 self.assertEqual(etree.tostring(result),
1727 _bytes('<?test TEST?><Y>XYZ</Y><!--TEST-->'))
1728
1730 tree = self.parse('<a><b>E</b></a>')
1731 style = self.parse('''\
1732 <xsl:stylesheet version="1.0"
1733 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1734 xmlns:myns="testns"
1735 extension-element-prefixes="myns">
1736 <xsl:template match="a">
1737 <xsl:variable name="testvar">yo</xsl:variable>
1738 <A>
1739 <myns:myext>
1740 <xsl:attribute name="attr">
1741 <xsl:value-of select="$testvar" />
1742 </xsl:attribute>
1743 <B>
1744 <xsl:choose>
1745 <xsl:when test="1 = 2"><C/></xsl:when>
1746 <xsl:otherwise><D><xsl:value-of select="b/text()" /></D></xsl:otherwise>
1747 </xsl:choose>
1748 </B>
1749 </myns:myext>
1750 </A>
1751 </xsl:template>
1752 </xsl:stylesheet>''')
1753
1754 class MyExt(etree.XSLTExtension):
1755 def execute(self, context, self_node, input_node, output_parent):
1756 el = etree.Element('MY')
1757 self.process_children(context, el)
1758 output_parent.append(el)
1759
1760 extensions = { ('testns', 'myext') : MyExt() }
1761
1762 result = tree.xslt(style, extensions=extensions)
1763 self.assertEqual(self._rootstring(result),
1764 _bytes('<A><MYattr="yo"><B><D>E</D></B></MY></A>'))
1765
1767 tree = self.parse('<a/>')
1768 style = self.parse('''\
1769 <xsl:stylesheet version="1.0"
1770 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1771 xmlns:myns="testns"
1772 extension-element-prefixes="myns">
1773 <xsl:template match="a">
1774 <myns:myext>
1775 <A/>
1776 </myns:myext>
1777 </xsl:template>
1778 </xsl:stylesheet>''')
1779
1780 class MyExt(etree.XSLTExtension):
1781 def execute(self, context, self_node, input_node, output_parent):
1782 self.process_children(context, output_parent)
1783
1784 extensions = { ('testns', 'myext') : MyExt() }
1785
1786 result = tree.xslt(style, extensions=extensions)
1787 self.assertEqual(self._rootstring(result),
1788 _bytes('<A/>'))
1789
1791 tree = self.parse('<a/>')
1792 style = self.parse('''\
1793 <xsl:stylesheet version="1.0"
1794 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1795 xmlns:myns="testns"
1796 extension-element-prefixes="myns">
1797 <xsl:template match="a">
1798 <myns:myext>
1799 <A/>
1800 </myns:myext>
1801 </xsl:template>
1802 </xsl:stylesheet>''')
1803
1804 class MyExt(etree.XSLTExtension):
1805 def execute(self, context, self_node, input_node, output_parent):
1806 self.process_children(context, self_node)
1807
1808 extensions = { ('testns', 'myext') : MyExt() }
1809
1810 self.assertRaises(TypeError, tree.xslt, style, extensions=extensions)
1811
1813 tree = self.parse('<a/>')
1814 style = self.parse('''\
1815 <xsl:stylesheet version="1.0"
1816 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1817 xmlns:myns="testns"
1818 extension-element-prefixes="myns">
1819 <xsl:template match="a">
1820 <myns:myext>
1821 <A><myns:myext><B/></myns:myext></A>
1822 </myns:myext>
1823 </xsl:template>
1824 </xsl:stylesheet>''')
1825
1826 class MyExt(etree.XSLTExtension):
1827 callback_call_counter = 0
1828 def execute(self, context, self_node, input_node, output_parent):
1829 self.callback_call_counter += 1
1830 el = etree.Element('MY', n=str(self.callback_call_counter))
1831 self.process_children(context, el)
1832 output_parent.append(el)
1833
1834 extensions = { ('testns', 'myext') : MyExt() }
1835
1836 result = tree.xslt(style, extensions=extensions)
1837 self.assertEqual(self._rootstring(result),
1838 _bytes('<MYn="1"><A><MYn="2"><B/></MY></A></MY>'))
1839
1841 tree = self.parse('<a><b>B</b></a>')
1842 style = self.parse('''\
1843 <xsl:stylesheet version="1.0"
1844 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1845 xmlns:myns="testns"
1846 extension-element-prefixes="myns"
1847 exclude-result-prefixes="myns">
1848 <xsl:template match="a">
1849 <A><myns:myext>b</myns:myext></A>
1850 </xsl:template>
1851 </xsl:stylesheet>''')
1852
1853 class MyError(Exception):
1854 pass
1855
1856 class MyExt(etree.XSLTExtension):
1857 def execute(self, context, self_node, input_node, output_parent):
1858 raise MyError("expected!")
1859
1860 extensions = { ('testns', 'myext') : MyExt() }
1861 self.assertRaises(MyError, tree.xslt, style, extensions=extensions)
1862
1863
1864
1866 tree = self.parse("""\
1867 <text>
1868 <par>This is <format>arbitrary</format> text in a paragraph</par>
1869 </text>""")
1870 style = self.parse("""\
1871 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my" extension-element-prefixes="my" version="1.0">
1872 <xsl:template match="par">
1873 <my:par><xsl:apply-templates /></my:par>
1874 </xsl:template>
1875 <xsl:template match="format">
1876 <my:format><xsl:apply-templates /></my:format>
1877 </xsl:template>
1878 </xsl:stylesheet>
1879 """)
1880 test = self
1881 calls = []
1882
1883 class ExtMyPar(etree.XSLTExtension):
1884 def execute(self, context, self_node, input_node, output_parent):
1885 calls.append('par')
1886 p = etree.Element("p")
1887 p.attrib["style"] = "color:red"
1888 self.process_children(context, p)
1889 output_parent.append(p)
1890
1891 class ExtMyFormat(etree.XSLTExtension):
1892 def execute(self, context, self_node, input_node, output_parent):
1893 calls.append('format')
1894 content = self.process_children(context)
1895 test.assertEqual(1, len(content))
1896 test.assertEqual('arbitrary', content[0])
1897 test.assertEqual('This is ', output_parent.text)
1898 output_parent.text += '*-%s-*' % content[0]
1899
1900 extensions = {("my", "par"): ExtMyPar(), ("my", "format"): ExtMyFormat()}
1901 transform = etree.XSLT(style, extensions=extensions)
1902 result = transform(tree)
1903 self.assertEqual(['par', 'format'], calls)
1904 self.assertEqual(
1905 b'<p style="color:red">This is *-arbitrary-* text in a paragraph</p>\n',
1906 etree.tostring(result))
1907
1910 """XSLT tests for etree under Python 3"""
1911
1912 pytestmark = skipif('sys.version_info < (3,0)')
1913
1915 tree = self.parse('<a><b>B</b><c>C</c></a>')
1916 style = self.parse('''\
1917 <xsl:stylesheet version="1.0"
1918 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1919 <xsl:template match="*" />
1920 <xsl:template match="/">
1921 <foo><xsl:value-of select="/a/b/text()" /></foo>
1922 </xsl:template>
1923 </xsl:stylesheet>''')
1924
1925 st = etree.XSLT(style)
1926 res = st(tree)
1927 self.assertEqual(_bytes('''\
1928 <?xml version="1.0"?>
1929 <foo>B</foo>
1930 '''),
1931 bytes(res))
1932
1934 tree = self.parse('<a><b>B</b><c>C</c></a>')
1935 style = self.parse('''\
1936 <xsl:stylesheet version="1.0"
1937 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1938 <xsl:template match="*" />
1939 <xsl:template match="/">
1940 <foo><xsl:value-of select="/a/b/text()" /></foo>
1941 </xsl:template>
1942 </xsl:stylesheet>''')
1943
1944 st = etree.XSLT(style)
1945 res = st(tree)
1946 self.assertEqual(_bytes('''\
1947 <?xml version="1.0"?>
1948 <foo>B</foo>
1949 '''),
1950 bytearray(res))
1951
1953 tree = self.parse('<a><b>B</b><c>C</c></a>')
1954 style = self.parse('''\
1955 <xsl:stylesheet version="1.0"
1956 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1957 <xsl:template match="*" />
1958 <xsl:template match="/">
1959 <foo><xsl:value-of select="/a/b/text()" /></foo>
1960 </xsl:template>
1961 </xsl:stylesheet>''')
1962
1963 st = etree.XSLT(style)
1964 res = st(tree)
1965 self.assertEqual(_bytes('''\
1966 <?xml version="1.0"?>
1967 <foo>B</foo>
1968 '''),
1969 bytes(memoryview(res)))
1970
1985
1986 if __name__ == '__main__':
1987 print('to test use test.py %s' % __file__)
1988