1
2
3 """
4 Test cases related to XSLT processing
5 """
6
7 import unittest, copy, sys, os.path
8
9 this_dir = os.path.dirname(__file__)
10 if this_dir not in sys.path:
11 sys.path.insert(0, this_dir)
12
13 is_python3 = sys.version_info[0] >= 3
14
15 try:
16 unicode
17 except NameError:
18 unicode = str
19
20 try:
21 basestring
22 except NameError:
23 basestring = str
24
25 from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir
26 from common_imports import doctest, _bytes, _str, make_doctest, skipif
27
29 """XSLT tests etree"""
30
32 tree = self.parse('<a><b>B</b><c>C</c></a>')
33 style = self.parse('''\
34 <xsl:stylesheet version="1.0"
35 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
36 <xsl:template match="*" />
37 <xsl:template match="/">
38 <foo><xsl:value-of select="/a/b/text()" /></foo>
39 </xsl:template>
40 </xsl:stylesheet>''')
41
42 st = etree.XSLT(style)
43 res = st(tree)
44 self.assertEqual('''\
45 <?xml version="1.0"?>
46 <foo>B</foo>
47 ''',
48 str(res))
49
52
55
57 style = self.parse('''\
58 <xsl:stylesheet version="1.0"
59 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
60 <xsl:stylesheet />
61 </xsl:stylesheet>''')
62
63 self.assertRaises(
64 etree.XSLTParseError, etree.XSLT, style)
65
67 tree = self.parse('<a><b>B</b><c>C</c></a>')
68 style = self.parse('''\
69 <xsl:stylesheet version="1.0"
70 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
71 <xsl:template match="*" />
72 <xsl:template match="/">
73 <foo><xsl:value-of select="/a/b/text()" /></foo>
74 </xsl:template>
75 </xsl:stylesheet>''')
76
77 transform = etree.XSLT(style)
78 res = transform(tree)
79 self.assertEqual('''\
80 <?xml version="1.0"?>
81 <foo>B</foo>
82 ''',
83 str(res))
84
85 transform_copy = copy.deepcopy(transform)
86 res = transform_copy(tree)
87 self.assertEqual('''\
88 <?xml version="1.0"?>
89 <foo>B</foo>
90 ''',
91 str(res))
92
93 transform = etree.XSLT(style)
94 res = transform(tree)
95 self.assertEqual('''\
96 <?xml version="1.0"?>
97 <foo>B</foo>
98 ''',
99 str(res))
100
102 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
103 ).decode("unicode_escape"))
104 style = self.parse('''\
105 <xsl:stylesheet version="1.0"
106 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
107 <xsl:output encoding="UTF-8"/>
108 <xsl:template match="/">
109 <foo><xsl:value-of select="/a/b/text()" /></foo>
110 </xsl:template>
111 </xsl:stylesheet>''')
112
113 st = etree.XSLT(style)
114 res = st(tree)
115 expected = _bytes('''\
116 <?xml version="1.0" encoding="UTF-8"?>
117 <foo>\\uF8D2</foo>
118 ''').decode("unicode_escape")
119 if is_python3:
120 self.assertEqual(expected,
121 str(bytes(res), 'UTF-8'))
122 else:
123 self.assertEqual(expected,
124 unicode(str(res), 'UTF-8'))
125
127 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
128 ).decode("unicode_escape"))
129 style = self.parse('''\
130 <xsl:stylesheet version="1.0"
131 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
132 <xsl:output encoding="UTF-16"/>
133 <xsl:template match="/">
134 <foo><xsl:value-of select="/a/b/text()" /></foo>
135 </xsl:template>
136 </xsl:stylesheet>''')
137
138 st = etree.XSLT(style)
139 res = st(tree)
140 expected = _bytes('''\
141 <?xml version="1.0" encoding="UTF-16"?>
142 <foo>\\uF8D2</foo>
143 ''').decode("unicode_escape")
144 if is_python3:
145 self.assertEqual(expected,
146 str(bytes(res), 'UTF-16'))
147 else:
148 self.assertEqual(expected,
149 unicode(str(res), 'UTF-16'))
150
152 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
153 ).decode("unicode_escape"))
154 style = self.parse('''\
155 <xsl:stylesheet version="1.0"
156 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
157 <xsl:output encoding="UTF-8"/>
158 <xsl:template match="/">
159 <foo><xsl:value-of select="/a/b/text()" /></foo>
160 </xsl:template>
161 </xsl:stylesheet>''')
162
163 st = etree.XSLT(style)
164 res = st(tree)
165 expected = _bytes("""\
166 <?xml version='1.0' encoding='UTF-16'?>\
167 <foo>\\uF8D2</foo>""").decode("unicode_escape")
168
169 f = BytesIO()
170 res.write(f, encoding='UTF-16')
171 if is_python3:
172 result = str(f.getvalue(), 'UTF-16').replace('\n', '')
173 else:
174 result = unicode(str(f.getvalue()), 'UTF-16').replace('\n', '')
175 self.assertEqual(expected, result)
176
178 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
179 ).decode("unicode_escape"))
180 style = self.parse('''\
181 <xsl:stylesheet version="1.0"
182 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
183 <xsl:output encoding="UTF-16"/>
184 <xsl:template match="/">
185 <foo><xsl:value-of select="/a/b/text()" /></foo>
186 </xsl:template>
187 </xsl:stylesheet>''')
188
189 st = etree.XSLT(style)
190 res = st(tree)
191 expected = _bytes('''\
192 <?xml version="1.0"?>
193 <foo>\\uF8D2</foo>
194 ''').decode("unicode_escape")
195 self.assertEqual(expected,
196 unicode(res))
197
199 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
200 ).decode("unicode_escape"))
201 style = self.parse('''\
202 <xsl:stylesheet version="1.0"
203 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
204 <xsl:output encoding="UTF-16" standalone="no"/>
205 <xsl:template match="/">
206 <foo><xsl:value-of select="/a/b/text()" /></foo>
207 </xsl:template>
208 </xsl:stylesheet>''')
209
210 st = etree.XSLT(style)
211 res = st(tree)
212 expected = _bytes('''\
213 <?xml version="1.0" standalone="no"?>
214 <foo>\\uF8D2</foo>
215 ''').decode("unicode_escape")
216 self.assertEqual(expected,
217 unicode(res))
218
231
248
250 style = self.parse('''\
251 <xsl:stylesheet version="1.0"
252 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
253 <xsl:foo />
254 </xsl:stylesheet>''')
255 self.assertRaises(etree.XSLTParseError,
256 etree.XSLT, style)
257
259 tree = self.parse('<a/>')
260 style = self.parse('''\
261 <xsl:stylesheet version="1.0"
262 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
263 <xsl:foo />
264 </xsl:stylesheet>''')
265 self.assertRaises(etree.XSLTParseError,
266 etree.XSLT, style)
267 exc = None
268 try:
269 etree.XSLT(tree)
270 except etree.XSLTParseError as e:
271 exc = e
272 else:
273 self.assertFalse(True, "XSLT processing should have failed but didn't")
274 self.assertTrue(exc is not None)
275 self.assertTrue(len(exc.error_log))
276 for error in exc.error_log:
277 self.assertTrue(':ERROR:XSLT:' in str(error))
278
280 tree = self.parse('<a><b>B</b><c>C</c></a>')
281 style = self.parse('''\
282 <xsl:stylesheet version="1.0"
283 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
284 <xsl:template match="/">
285 <foo><xsl:value-of select="$bar" /></foo>
286 </xsl:template>
287 </xsl:stylesheet>''')
288
289 st = etree.XSLT(style)
290 res = st(tree, bar="'Bar'")
291 self.assertEqual('''\
292 <?xml version="1.0"?>
293 <foo>Bar</foo>
294 ''',
295 str(res))
296
298 tree = self.parse('<a><b>B</b><c>C</c></a>')
299 style = self.parse('''\
300 <xsl:stylesheet version="1.0"
301 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
302 <xsl:template match="/">
303 <foo><xsl:value-of select="$bar" /></foo>
304 </xsl:template>
305 </xsl:stylesheet>''')
306
307 st = etree.XSLT(style)
308 res = st(tree, bar=etree.XSLT.strparam('''it's me, "Bar"'''))
309 self.assertEqual('''\
310 <?xml version="1.0"?>
311 <foo>it's me, "Bar"</foo>
312 ''',
313 str(res))
314
316 tree = self.parse('<a><b>B</b><c>C</c></a>')
317 style = self.parse('''\
318 <xsl:stylesheet version="1.0"
319 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
320 <xsl:param name="bar"/>
321 <xsl:template match="/">
322 <foo><xsl:value-of select="$bar" /></foo>
323 </xsl:template>
324 </xsl:stylesheet>''')
325
326 st = etree.XSLT(style)
327 res = self.assertRaises(etree.XSLTApplyError,
328 st, tree, bar="<test/>")
329 res = self.assertRaises(etree.XSLTApplyError,
330 st, tree, bar="....")
331
333
334 tree = self.parse('<a><b>B</b><c>C</c></a>')
335 style = self.parse('''\
336 <xsl:stylesheet version="1.0"
337 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
338 <xsl:template match="/">
339 <foo><xsl:value-of select="$bar" /></foo>
340 </xsl:template>
341 </xsl:stylesheet>''')
342
343 st = etree.XSLT(style)
344
345 self.assertRaises(etree.XSLTApplyError, st.apply, tree)
346
348 tree = self.parse('<a><b>B</b><c>C</c></a>')
349 style = self.parse('''\
350 <xsl:stylesheet version="1.0"
351 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
352 <xsl:template match="*" />
353 <xsl:template match="/">
354 <foo><xsl:value-of select="$bar" /></foo>
355 <foo><xsl:value-of select="$baz" /></foo>
356 </xsl:template>
357 </xsl:stylesheet>''')
358
359 st = etree.XSLT(style)
360 res = st(tree, bar="'Bar'", baz="'Baz'")
361 self.assertEqual('''\
362 <?xml version="1.0"?>
363 <foo>Bar</foo><foo>Baz</foo>
364 ''',
365 str(res))
366
368 tree = self.parse('<a><b>B</b><c>C</c></a>')
369 style = self.parse('''\
370 <xsl:stylesheet version="1.0"
371 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
372 <xsl:template match="*" />
373 <xsl:template match="/">
374 <foo><xsl:value-of select="$bar" /></foo>
375 </xsl:template>
376 </xsl:stylesheet>''')
377
378 st = etree.XSLT(style)
379 res = st(tree, bar="/a/b/text()")
380 self.assertEqual('''\
381 <?xml version="1.0"?>
382 <foo>B</foo>
383 ''',
384 str(res))
385
387 tree = self.parse('<a><b>B</b><c>C</c></a>')
388 style = self.parse('''\
389 <xsl:stylesheet version="1.0"
390 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
391 <xsl:template match="*" />
392 <xsl:template match="/">
393 <foo><xsl:value-of select="$bar" /></foo>
394 </xsl:template>
395 </xsl:stylesheet>''')
396
397 st = etree.XSLT(style)
398 res = st(tree, bar=etree.XPath("/a/b/text()"))
399 self.assertEqual('''\
400 <?xml version="1.0"?>
401 <foo>B</foo>
402 ''',
403 str(res))
404
406 tree = self.parse('<a><b>B</b><c>C</c></a>')
407 style = self.parse('''\
408 <xsl:stylesheet version="1.0"
409 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
410 <xsl:param name="bar" select="'Default'" />
411 <xsl:template match="*" />
412 <xsl:template match="/">
413 <foo><xsl:value-of select="$bar" /></foo>
414 </xsl:template>
415 </xsl:stylesheet>''')
416
417 st = etree.XSLT(style)
418 res = st(tree, bar="'Bar'")
419 self.assertEqual('''\
420 <?xml version="1.0"?>
421 <foo>Bar</foo>
422 ''',
423 str(res))
424 res = st(tree)
425 self.assertEqual('''\
426 <?xml version="1.0"?>
427 <foo>Default</foo>
428 ''',
429 str(res))
430
432 tree = self.parse('<a><b>B</b><c>C</c></a>')
433 style = self.parse('''\
434 <xsl:stylesheet version="1.0"
435 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
436 <xsl:output method="html"/>
437 <xsl:strip-space elements="*"/>
438 <xsl:template match="/">
439 <html><body><xsl:value-of select="/a/b/text()" /></body></html>
440 </xsl:template>
441 </xsl:stylesheet>''')
442
443 st = etree.XSLT(style)
444 res = st(tree)
445 self.assertEqual('<html><body>B</body></html>',
446 str(res).strip())
447
451
457
480
505
507
508 xml = '<blah/>'
509 xslt = '''
510 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
511 <xsl:template match="/" />
512 </xsl:stylesheet>
513 '''
514
515 source = self.parse(xml)
516 styledoc = self.parse(xslt)
517 style = etree.XSLT(styledoc)
518 result = style(source)
519 self.assertEqual('', str(result))
520
522 xml = '<blah/>'
523 xslt = '''
524 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
525 <xsl:template match="/">
526 <xsl:message>TEST TEST TEST</xsl:message>
527 </xsl:template>
528 </xsl:stylesheet>
529 '''
530
531 source = self.parse(xml)
532 styledoc = self.parse(xslt)
533 style = etree.XSLT(styledoc)
534 result = style(source)
535 self.assertEqual('', str(result))
536 self.assertTrue("TEST TEST TEST" in [entry.message
537 for entry in style.error_log])
538
540 xml = '<blah/>'
541 xslt = '''
542 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
543 <xsl:template match="/">
544 <xsl:message terminate="yes">TEST TEST TEST</xsl:message>
545 </xsl:template>
546 </xsl:stylesheet>
547 '''
548
549 source = self.parse(xml)
550 styledoc = self.parse(xslt)
551 style = etree.XSLT(styledoc)
552
553 self.assertRaises(etree.XSLTApplyError, style, source)
554 self.assertTrue("TEST TEST TEST" in [entry.message
555 for entry in style.error_log])
556
558 tree = self.parse('<a><b>B</b><c>C</c></a>')
559 style = self.parse('''\
560 <xsl:stylesheet version="1.0"
561 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
562 <xsl:template match="*" />
563 <xsl:template match="/">
564 <doc>
565 <foo><xsl:value-of select="$bar" /></foo>
566 <foo><xsl:value-of select="$baz" /></foo>
567 </doc>
568 </xsl:template>
569 </xsl:stylesheet>''')
570
571 result = tree.xslt(style, bar="'Bar'", baz="'Baz'")
572 self.assertEqual(
573 _bytes('<doc><foo>Bar</foo><foo>Baz</foo></doc>'),
574 etree.tostring(result.getroot()))
575
577 tree = self.parse('<a><b>B</b><c>C</c></a>')
578 style = self.parse('''\
579 <xsl:stylesheet version="1.0"
580 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
581 <xsl:template match="a"><A><xsl:apply-templates/></A></xsl:template>
582 <xsl:template match="b"><B><xsl:apply-templates/></B></xsl:template>
583 <xsl:template match="c"><C><xsl:apply-templates/></C></xsl:template>
584 </xsl:stylesheet>''')
585
586 self.assertEqual(self._rootstring(tree),
587 _bytes('<a><b>B</b><c>C</c></a>'))
588 result = tree.xslt(style)
589 self.assertEqual(self._rootstring(tree),
590 _bytes('<a><b>B</b><c>C</c></a>'))
591 self.assertEqual(self._rootstring(result),
592 _bytes('<A><B>B</B><C>C</C></A>'))
593
594 b_tree = etree.ElementTree(tree.getroot()[0])
595 self.assertEqual(self._rootstring(b_tree),
596 _bytes('<b>B</b>'))
597 result = b_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('<B>B</B>'))
602
603 c_tree = etree.ElementTree(tree.getroot()[1])
604 self.assertEqual(self._rootstring(c_tree),
605 _bytes('<c>C</c>'))
606 result = c_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('<C>C</C>'))
611
613
614 xslt = etree.XSLT(etree.XML("""\
615 <xsl:stylesheet version="1.0"
616 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
617 <xsl:template match="/">
618 <test>TEXT<xsl:copy-of select="document('')//test"/></test>
619 </xsl:template>
620 </xsl:stylesheet>
621 """))
622 result = xslt(etree.XML('<a/>'))
623 root = result.getroot()
624 self.assertEqual(root.tag,
625 'test')
626 self.assertEqual(root[0].tag,
627 'test')
628 self.assertEqual(root[0].text,
629 'TEXT')
630 self.assertEqual(root[0][0].tag,
631 '{http://www.w3.org/1999/XSL/Transform}copy-of')
632
642
652
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('uri:__junkfood__is__evil__')//test"/></test>
659 </xsl:template>
660 </xsl:stylesheet>
661 """))
662
663 errors = None
664 try:
665 xslt(etree.XML('<a/>'))
666 except etree.XSLTApplyError as exc:
667 errors = exc.error_log
668 else:
669 self.assertFalse(True, "XSLT processing should have failed but didn't")
670
671 self.assertTrue(len(errors))
672 for error in errors:
673 if ':ERROR:XSLT:' in str(error):
674 break
675 else:
676 self.assertFalse(True, 'No XSLT errors found in error log:\n%s' % errors)
677
679
680 assertEqual = self.assertEqual
681 called = {'count' : 0}
682 class TestResolver(etree.Resolver):
683 def resolve(self, url, id, context):
684 assertEqual(url, 'file://ANYTHING')
685 called['count'] += 1
686 return self.resolve_string('<CALLED/>', context)
687
688 parser = etree.XMLParser()
689 parser.resolvers.add(TestResolver())
690
691 xslt = etree.XSLT(etree.XML(_bytes("""\
692 <xsl:stylesheet version="1.0"
693 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
694 xmlns:l="local">
695 <xsl:template match="/">
696 <test>
697 <xsl:for-each select="document('')//l:data/l:entry">
698 <xsl:copy-of select="document('file://ANYTHING')"/>
699 <xsl:copy>
700 <xsl:attribute name="value">
701 <xsl:value-of select="."/>
702 </xsl:attribute>
703 </xsl:copy>
704 </xsl:for-each>
705 </test>
706 </xsl:template>
707 <l:data>
708 <l:entry>A</l:entry>
709 <l:entry>B</l:entry>
710 </l:data>
711 </xsl:stylesheet>
712 """), parser))
713
714 self.assertEqual(called['count'], 0)
715 result = xslt(etree.XML('<a/>'))
716 self.assertEqual(called['count'], 1)
717
718 root = result.getroot()
719 self.assertEqual(root.tag,
720 'test')
721 self.assertEqual(len(root), 4)
722
723 self.assertEqual(root[0].tag,
724 'CALLED')
725 self.assertEqual(root[1].tag,
726 '{local}entry')
727 self.assertEqual(root[1].text,
728 None)
729 self.assertEqual(root[1].get("value"),
730 'A')
731 self.assertEqual(root[2].tag,
732 'CALLED')
733 self.assertEqual(root[3].tag,
734 '{local}entry')
735 self.assertEqual(root[3].text,
736 None)
737 self.assertEqual(root[3].get("value"),
738 'B')
739
741 assertEqual = self.assertEqual
742 called = {'count' : 0}
743 expected_url = None
744 class TestResolver(etree.Resolver):
745 def resolve(self, url, id, context):
746 assertEqual(url, expected_url)
747 called['count'] += 1
748 return self.resolve_string('<CALLED/>', context)
749
750 stylesheet_xml = _bytes("""\
751 <xsl:stylesheet version="1.0"
752 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
753 xmlns:l="local">
754 <xsl:template match="/">
755 <xsl:copy-of select="document('test.xml')"/>
756 </xsl:template>
757 </xsl:stylesheet>
758 """)
759
760 parser = etree.XMLParser()
761 parser.resolvers.add(TestResolver())
762
763
764 expected_url = 'test.xml'
765 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser))
766
767 self.assertEqual(called['count'], 0)
768 result = xslt(etree.XML('<a/>'))
769 self.assertEqual(called['count'], 1)
770
771
772 called['count'] = 0
773 expected_url = 'MY/BASE/test.xml'
774 xslt = etree.XSLT(etree.XML(
775 stylesheet_xml, parser,
776 base_url=os.path.join('MY', 'BASE', 'FILE')))
777
778 self.assertEqual(called['count'], 0)
779 result = xslt(etree.XML('<a/>'))
780 self.assertEqual(called['count'], 1)
781
782
783 called['count'] = 0
784 expected_url = 'http://server.com/BASE/DIR/test.xml'
785 xslt = etree.XSLT(etree.XML(
786 stylesheet_xml, parser,
787 base_url='http://server.com/BASE/DIR/FILE'))
788
789 self.assertEqual(called['count'], 0)
790 result = xslt(etree.XML('<a/>'))
791 self.assertEqual(called['count'], 1)
792
793
794 called['count'] = 0
795 expected_url = 'file://BASE/DIR/test.xml'
796 xslt = etree.XSLT(etree.XML(
797 stylesheet_xml, parser,
798 base_url='file://BASE/DIR/FILE'))
799
800 self.assertEqual(called['count'], 0)
801 result = xslt(etree.XML('<a/>'))
802 self.assertEqual(called['count'], 1)
803
814
820
826
835
837 root = etree.XML(_bytes('''\
838 <transform>
839 <widget displayType="fieldset"/>
840 </transform>'''))
841
842 xslt = etree.XSLT(etree.XML(_bytes('''\
843 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
844 <xsl:output method="html" indent="no"/>
845 <xsl:template match="/">
846 <html>
847 <xsl:apply-templates/>
848 </html>
849 </xsl:template>
850
851 <xsl:template match="widget">
852 <xsl:element name="{@displayType}"/>
853 </xsl:template>
854
855 </xsl:stylesheet>''')))
856
857 result = xslt(root[0])
858 root[:] = result.getroot()[:]
859 del root
860
862 tree = self.parse('''\
863 <?xml version="1.0"?>
864 <?xml-stylesheet type="text/xsl" href="%s"?>
865 <a>
866 <b>B</b>
867 <c>C</c>
868 </a>''' % fileInTestDir("test1.xslt"))
869
870 style_root = tree.getroot().getprevious().parseXSL().getroot()
871 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
872 style_root.tag)
873
875
876 tree = self.parse('''\
877 <?xml version="1.0"?>
878 <?xml-stylesheet type="text/xsl" href="#style"?>
879 <a>
880 <b>B</b>
881 <c>C</c>
882 <xsl:stylesheet version="1.0" xml:id="style"
883 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
884 <xsl:template match="*" />
885 <xsl:template match="/">
886 <foo><xsl:value-of select="/a/b/text()" /></foo>
887 </xsl:template>
888 </xsl:stylesheet>
889 </a>''')
890
891 style_root = tree.getroot().getprevious().parseXSL().getroot()
892 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
893 style_root.tag)
894
895 st = etree.XSLT(style_root)
896 res = st(tree)
897 self.assertEqual('''\
898 <?xml version="1.0"?>
899 <foo>B</foo>
900 ''',
901 str(res))
902
904
905 tree = self.parse('''\
906 <?xml version="1.0"?>
907 <?xml-stylesheet type="text/xsl" href="#style"?>
908 <a>
909 <b>B</b>
910 <c>C</c>
911 </a>''')
912
913 style = self.parse('''\
914 <xsl:stylesheet version="1.0" xml:id="style"
915 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
916 <xsl:template match="*" />
917 <xsl:template match="/">
918 <foo><xsl:value-of select="/a/b/text()" /></foo>
919 </xsl:template>
920 </xsl:stylesheet>
921 ''')
922
923 tree.getroot().append(style.getroot())
924
925 style_root = tree.getroot().getprevious().parseXSL().getroot()
926 self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet",
927 style_root.tag)
928
929 st = etree.XSLT(style_root)
930 res = st(tree)
931 self.assertEqual('''\
932 <?xml version="1.0"?>
933 <foo>B</foo>
934 ''',
935 str(res))
936
938 tree = self.parse('''\
939 <?xml version="1.0"?>
940 <?xml-stylesheet type="text/xsl" href="TEST"?>
941 <a>
942 <b>B</b>
943 <c>C</c>
944 </a>''')
945
946 pi = tree.getroot().getprevious()
947 self.assertEqual("TEST", pi.get("href"))
948
950 tree = self.parse('''\
951 <?xml version="1.0"?>
952 <?xml-stylesheet type="text/xsl" href="TEST"?>
953 <a>
954 <b>B</b>
955 <c>C</c>
956 </a>''')
957
958 pi = tree.getroot().getprevious()
959 self.assertEqual("TEST", pi.get("href"))
960 self.assertEqual("text/xsl", pi.get("type"))
961 self.assertEqual(None, pi.get("motz"))
962
964 tree = self.parse('''\
965 <?xml version="1.0"?>
966 <?xml-stylesheet href="TEST" type="text/xsl"?>
967 <a>
968 <b>B</b>
969 <c>C</c>
970 </a>''')
971
972 pi = tree.getroot().getprevious()
973 self.assertEqual("TEST", pi.get("href"))
974 self.assertEqual("text/xsl", pi.get("type"))
975 self.assertEqual(None, pi.get("motz"))
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(None, pi.get("unknownattribute"))
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
1001 pi.set("href", "TEST123")
1002 self.assertEqual("TEST123", pi.get("href"))
1003
1005 tree = self.parse('''\
1006 <?xml version="1.0"?>
1007 <?xml-stylesheet type="text/xsl"?>
1008 <a>
1009 <b>B</b>
1010 <c>C</c>
1011 </a>''')
1012
1013 pi = tree.getroot().getprevious()
1014 self.assertEqual(None, pi.get("href"))
1015
1016 pi.set("href", "TEST")
1017 self.assertEqual("TEST", pi.get("href"))
1018
1020 """EXSLT tests"""
1021
1023 tree = self.parse('<a><b>B</b><c>C</c></a>')
1024 style = self.parse('''\
1025 <xsl:stylesheet version="1.0"
1026 xmlns:str="http://exslt.org/strings"
1027 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1028 exclude-result-prefixes="str xsl">
1029 <xsl:template match="text()">
1030 <xsl:value-of select="str:align(string(.), '***', 'center')" />
1031 </xsl:template>
1032 <xsl:template match="*">
1033 <xsl:copy>
1034 <xsl:apply-templates/>
1035 </xsl:copy>
1036 </xsl:template>
1037 </xsl:stylesheet>''')
1038
1039 st = etree.XSLT(style)
1040 res = st(tree)
1041 self.assertEqual('''\
1042 <?xml version="1.0"?>
1043 <a><b>*B*</b><c>*C*</c></a>
1044 ''',
1045 str(res))
1046
1048 tree = self.parse('<a><b>B</b><c>C</c></a>')
1049 style = self.parse('''\
1050 <xsl:stylesheet version = "1.0"
1051 xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
1052 xmlns:str="http://exslt.org/strings"
1053 extension-element-prefixes="str">
1054
1055 <xsl:template match="/">
1056 <h1 class="{str:replace('abc', 'b', 'x')}">test</h1>
1057 </xsl:template>
1058
1059 </xsl:stylesheet>''')
1060
1061 st = etree.XSLT(style)
1062 res = st(tree)
1063 self.assertEqual(str(res), '''\
1064 <?xml version="1.0"?>
1065 <h1 class="axc">test</h1>
1066 ''')
1067
1069 tree = self.parse('<a><b>B</b><c>C</c></a>')
1070 style = self.parse('''\
1071 <xsl:stylesheet version="1.0"
1072 xmlns:math="http://exslt.org/math"
1073 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1074 exclude-result-prefixes="math xsl">
1075 <xsl:template match="*">
1076 <xsl:copy>
1077 <xsl:attribute name="pi">
1078 <xsl:value-of select="math:constant('PI', count(*)+2)"/>
1079 </xsl:attribute>
1080 <xsl:apply-templates/>
1081 </xsl:copy>
1082 </xsl:template>
1083 </xsl:stylesheet>''')
1084
1085 st = etree.XSLT(style)
1086 res = st(tree)
1087 self.assertEqual('''\
1088 <?xml version="1.0"?>
1089 <a pi="3.14"><b pi="3">B</b><c pi="3">C</c></a>
1090 ''',
1091 str(res))
1092
1094 xslt = etree.XSLT(etree.XML(_bytes("""\
1095 <xsl:stylesheet version="1.0"
1096 xmlns:regexp="http://exslt.org/regular-expressions"
1097 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1098 <xsl:template match="*">
1099 <test><xsl:copy-of select="*[regexp:test(string(.), '8.')]"/></test>
1100 </xsl:template>
1101 </xsl:stylesheet>
1102 """)))
1103 result = xslt(etree.XML(_bytes('<a><b>123</b><b>098</b><b>987</b></a>')))
1104 root = result.getroot()
1105 self.assertEqual(root.tag,
1106 'test')
1107 self.assertEqual(len(root), 1)
1108 self.assertEqual(root[0].tag,
1109 'b')
1110 self.assertEqual(root[0].text,
1111 '987')
1112
1114 xslt = etree.XSLT(etree.XML("""\
1115 <xsl:stylesheet version="1.0"
1116 xmlns:regexp="http://exslt.org/regular-expressions"
1117 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1118 <xsl:template match="*">
1119 <test>
1120 <xsl:copy-of select="regexp:replace(string(.), 'd.', '', 'XX')"/>
1121 <xsl:text>-</xsl:text>
1122 <xsl:copy-of select="regexp:replace(string(.), 'd.', 'gi', 'XX')"/>
1123 </test>
1124 </xsl:template>
1125 </xsl:stylesheet>
1126 """))
1127 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1128 root = result.getroot()
1129 self.assertEqual(root.tag,
1130 'test')
1131 self.assertEqual(len(root), 0)
1132 self.assertEqual(root.text, 'abXXdEeDed-abXXXXeXXd')
1133
1135 xslt = etree.XSLT(etree.XML("""\
1136 <xsl:stylesheet version="1.0"
1137 xmlns:regexp="http://exslt.org/regular-expressions"
1138 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1139 <xsl:template match="*">
1140 <test>
1141 <test1><xsl:copy-of select="regexp:match(string(.), 'd.')"/></test1>
1142 <test2><xsl:copy-of select="regexp:match(string(.), 'd.', 'g')"/></test2>
1143 <test2i><xsl:copy-of select="regexp:match(string(.), 'd.', 'gi')"/></test2i>
1144 </test>
1145 </xsl:template>
1146 </xsl:stylesheet>
1147 """))
1148 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1149 root = result.getroot()
1150 self.assertEqual(root.tag, 'test')
1151 self.assertEqual(len(root), 3)
1152
1153 self.assertEqual(len(root[0]), 1)
1154 self.assertEqual(root[0][0].tag, 'match')
1155 self.assertEqual(root[0][0].text, 'dC')
1156
1157 self.assertEqual(len(root[1]), 2)
1158 self.assertEqual(root[1][0].tag, 'match')
1159 self.assertEqual(root[1][0].text, 'dC')
1160 self.assertEqual(root[1][1].tag, 'match')
1161 self.assertEqual(root[1][1].text, 'dE')
1162
1163 self.assertEqual(len(root[2]), 3)
1164 self.assertEqual(root[2][0].tag, 'match')
1165 self.assertEqual(root[2][0].text, 'dC')
1166 self.assertEqual(root[2][1].tag, 'match')
1167 self.assertEqual(root[2][1].text, 'dE')
1168 self.assertEqual(root[2][2].tag, 'match')
1169 self.assertEqual(root[2][2].text, 'De')
1170
1172 xslt = etree.XSLT(etree.XML(_bytes("""\
1173 <xsl:stylesheet version="1.0"
1174 xmlns:regexp="http://exslt.org/regular-expressions"
1175 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1176 <xsl:template match="/">
1177 <test>
1178 <xsl:for-each select="regexp:match(
1179 '123abc567', '([0-9]+)([a-z]+)([0-9]+)' )">
1180 <test1><xsl:value-of select="."/></test1>
1181 </xsl:for-each>
1182 </test>
1183 </xsl:template>
1184 </xsl:stylesheet>
1185 """)))
1186 result = xslt(etree.XML(_bytes('<a/>')))
1187 root = result.getroot()
1188 self.assertEqual(root.tag, 'test')
1189 self.assertEqual(len(root), 4)
1190
1191 self.assertEqual(root[0].text, "123abc567")
1192 self.assertEqual(root[1].text, "123")
1193 self.assertEqual(root[2].text, "abc")
1194 self.assertEqual(root[3].text, "567")
1195
1197
1198 xslt = etree.XSLT(etree.XML(_bytes("""\
1199 <xsl:stylesheet version="1.0"
1200 xmlns:regexp="http://exslt.org/regular-expressions"
1201 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1202 <xsl:template match="/">
1203 <test>
1204 <xsl:for-each select="regexp:match(
1205 'http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml',
1206 '(\\w+):\\/\\/([^/:]+)(:\\d*)?([^# ]*)')">
1207 <test1><xsl:value-of select="."/></test1>
1208 </xsl:for-each>
1209 </test>
1210 </xsl:template>
1211 </xsl:stylesheet>
1212 """)))
1213 result = xslt(etree.XML(_bytes('<a/>')))
1214 root = result.getroot()
1215 self.assertEqual(root.tag, 'test')
1216 self.assertEqual(len(root), 5)
1217
1218 self.assertEqual(
1219 root[0].text,
1220 "http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml")
1221 self.assertEqual(
1222 root[1].text,
1223 "http")
1224 self.assertEqual(
1225 root[2].text,
1226 "www.bayes.co.uk")
1227 self.assertFalse(root[3].text)
1228 self.assertEqual(
1229 root[4].text,
1230 "/xml/index.xml?/xml/utils/rechecker.xml")
1231
1233
1234 xslt = etree.XSLT(self.parse("""\
1235 <xsl:stylesheet version="1.0"
1236 xmlns:regexp="http://exslt.org/regular-expressions"
1237 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1238 <xsl:template match="/">
1239 <test>
1240 <xsl:for-each select="regexp:match(
1241 'This is a test string', '(\\w+)', 'g')">
1242 <test1><xsl:value-of select="."/></test1>
1243 </xsl:for-each>
1244 </test>
1245 </xsl:template>
1246 </xsl:stylesheet>
1247 """))
1248 result = xslt(etree.XML(_bytes('<a/>')))
1249 root = result.getroot()
1250 self.assertEqual(root.tag, 'test')
1251 self.assertEqual(len(root), 5)
1252
1253 self.assertEqual(root[0].text, "This")
1254 self.assertEqual(root[1].text, "is")
1255 self.assertEqual(root[2].text, "a")
1256 self.assertEqual(root[3].text, "test")
1257 self.assertEqual(root[4].text, "string")
1258
1260
1261
1262 xslt = etree.XSLT(etree.XML(_bytes("""\
1263 <xsl:stylesheet version="1.0"
1264 xmlns:regexp="http://exslt.org/regular-expressions"
1265 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1266 <xsl:template match="/">
1267 <test>
1268 <xsl:for-each select="regexp:match(
1269 'This is a test string', '([a-z])+ ', 'g')">
1270 <test1><xsl:value-of select="."/></test1>
1271 </xsl:for-each>
1272 </test>
1273 </xsl:template>
1274 </xsl:stylesheet>
1275 """)))
1276 result = xslt(etree.XML(_bytes('<a/>')))
1277 root = result.getroot()
1278 self.assertEqual(root.tag, 'test')
1279 self.assertEqual(len(root), 4)
1280
1281 self.assertEqual(root[0].text, "his")
1282 self.assertEqual(root[1].text, "is")
1283 self.assertEqual(root[2].text, "a")
1284 self.assertEqual(root[3].text, "test")
1285
1287
1288
1289 xslt = etree.XSLT(etree.XML(_bytes("""\
1290 <xsl:stylesheet version="1.0"
1291 xmlns:regexp="http://exslt.org/regular-expressions"
1292 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1293 <xsl:template match="/">
1294 <test>
1295 <xsl:for-each select="regexp:match(
1296 'This is a test string', '([a-z])+ ', 'gi')">
1297 <test1><xsl:value-of select="."/></test1>
1298 </xsl:for-each>
1299 </test>
1300 </xsl:template>
1301 </xsl:stylesheet>
1302 """)))
1303 result = xslt(etree.XML(_bytes('<a/>')))
1304 root = result.getroot()
1305 self.assertEqual(root.tag, 'test')
1306 self.assertEqual(len(root), 4)
1307
1308 self.assertEqual(root[0].text, "This")
1309 self.assertEqual(root[1].text, "is")
1310 self.assertEqual(root[2].text, "a")
1311 self.assertEqual(root[3].text, "test")
1312
1313
1314 -class ETreeXSLTExtFuncTestCase(HelperTestCase):
1315 """Tests for XPath extension functions in XSLT."""
1316
1317 - def test_extensions1(self):
1318 tree = self.parse('<a><b>B</b></a>')
1319 style = self.parse('''\
1320 <xsl:stylesheet version="1.0"
1321 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1322 xmlns:myns="testns"
1323 exclude-result-prefixes="myns">
1324 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
1325 </xsl:stylesheet>''')
1326
1327 def mytext(ctxt, values):
1328 return 'X' * len(values)
1329
1330 result = tree.xslt(style, {('testns', 'mytext') : mytext})
1331 self.assertEqual(self._rootstring(result),
1332 _bytes('<A>X</A>'))
1333
1334 - def test_extensions2(self):
1335 tree = self.parse('<a><b>B</b></a>')
1336 style = self.parse('''\
1337 <xsl:stylesheet version="1.0"
1338 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1339 xmlns:myns="testns"
1340 exclude-result-prefixes="myns">
1341 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
1342 </xsl:stylesheet>''')
1343
1344 def mytext(ctxt, values):
1345 return 'X' * len(values)
1346
1347 namespace = etree.FunctionNamespace('testns')
1348 namespace['mytext'] = mytext
1349
1350 result = tree.xslt(style)
1351 self.assertEqual(self._rootstring(result),
1352 _bytes('<A>X</A>'))
1353
1355 tree = self.parse('<a><b>B</b><b/></a>')
1356 style = self.parse('''\
1357 <xsl:stylesheet version="1.0"
1358 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1359 xmlns:myns="testns"
1360 exclude-result-prefixes="myns">
1361 <xsl:template match="a">
1362 <xsl:variable name="content">
1363 <xsl:apply-templates/>
1364 </xsl:variable>
1365 <A><xsl:value-of select="myns:mytext($content)"/></A>
1366 </xsl:template>
1367 <xsl:template match="b"><xsl:copy>BBB</xsl:copy></xsl:template>
1368 </xsl:stylesheet>''')
1369
1370 def mytext(ctxt, values):
1371 for value in values:
1372 self.assertTrue(hasattr(value, 'tag'),
1373 "%s is not an Element" % type(value))
1374 self.assertEqual(value.tag, 'b')
1375 self.assertEqual(value.text, 'BBB')
1376 return 'X'.join([el.tag for el in values])
1377
1378 namespace = etree.FunctionNamespace('testns')
1379 namespace['mytext'] = mytext
1380
1381 result = tree.xslt(style)
1382 self.assertEqual(self._rootstring(result),
1383 _bytes('<A>bXb</A>'))
1384
1386 tree = self.parse('<a><b>B<c/>C</b><b/></a>')
1387 style = self.parse('''\
1388 <xsl:stylesheet version="1.0"
1389 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1390 xmlns:myns="testns"
1391 exclude-result-prefixes="myns">
1392 <xsl:template match="b">
1393 <A><xsl:value-of select="myns:myext()"/></A>
1394 </xsl:template>
1395 </xsl:stylesheet>''')
1396
1397 def extfunc(ctxt):
1398 text_content = ctxt.context_node.xpath('text()')
1399 return 'x'.join(text_content)
1400
1401 namespace = etree.FunctionNamespace('testns')
1402 namespace['myext'] = extfunc
1403
1404 result = tree.xslt(style)
1405 self.assertEqual(self._rootstring(result),
1406 _bytes('<A>BxC</A>'))
1407
1409
1410 class Resolver(etree.Resolver):
1411 def resolve(self, system_url, public_id, context):
1412 assert system_url == 'extdoc.xml'
1413 return self.resolve_string(b'<a><b>B<c/>C</b><b/></a>', context)
1414
1415 parser = etree.XMLParser()
1416 parser.resolvers.add(Resolver())
1417
1418 tree = self.parse(b'<a><b/><b/></a>')
1419 transform = etree.XSLT(self.parse(b'''\
1420 <xsl:stylesheet version="1.0"
1421 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1422 xmlns:mypre="testns"
1423 exclude-result-prefixes="mypre">
1424 <xsl:template match="b">
1425 <B><xsl:value-of select="mypre:myext()"/></B>
1426 </xsl:template>
1427 <xsl:template match="a">
1428 <A><xsl:apply-templates select="document('extdoc.xml')//b" /></A>
1429 </xsl:template>
1430 </xsl:stylesheet>''', parser=parser))
1431
1432 def extfunc(ctxt):
1433 text_content = ctxt.context_node.xpath('text()')
1434 return 'x'.join(text_content)
1435
1436 namespace = etree.FunctionNamespace('testns')
1437 namespace['myext'] = extfunc
1438
1439 result = transform(tree)
1440 self.assertEqual(self._rootstring(result),
1441 _bytes('<A><B>BxC</B><B/></A>'))
1442
1443
1444 -class ETreeXSLTExtElementTestCase(HelperTestCase):
1445 """Tests for extension elements in XSLT."""
1446
1448 tree = self.parse('<a><b>B</b></a>')
1449 style = self.parse('''\
1450 <xsl:stylesheet version="1.0"
1451 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1452 xmlns:myns="testns"
1453 extension-element-prefixes="myns"
1454 exclude-result-prefixes="myns">
1455 <xsl:template match="a">
1456 <A><myns:myext>b</myns:myext></A>
1457 </xsl:template>
1458 </xsl:stylesheet>''')
1459
1460 class MyExt(etree.XSLTExtension):
1461 def execute(self, context, self_node, input_node, output_parent):
1462 child = etree.Element(self_node.text)
1463 child.text = 'X'
1464 output_parent.append(child)
1465
1466 extensions = { ('testns', 'myext') : MyExt() }
1467
1468 result = tree.xslt(style, extensions=extensions)
1469 self.assertEqual(self._rootstring(result),
1470 _bytes('<A><b>X</b></A>'))
1471
1473 tree = self.parse('<a><b>B</b></a>')
1474 style = self.parse('''\
1475 <xsl:stylesheet version="1.0"
1476 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1477 xmlns:myns="testns"
1478 extension-element-prefixes="myns"
1479 exclude-result-prefixes="myns">
1480 <xsl:template match="/">
1481 <A><myns:myext>b</myns:myext></A>
1482 </xsl:template>
1483 </xsl:stylesheet>''')
1484
1485 tags = []
1486
1487 class MyExt(etree.XSLTExtension):
1488 def execute(self, context, self_node, input_node, output_parent):
1489 tags.append(input_node.tag)
1490
1491 extensions = { ('testns', 'myext') : MyExt() }
1492
1493 result = tree.xslt(style, extensions=extensions)
1494 self.assertEqual(tags, ['a'])
1495
1497 tree = self.parse('<?test toast?><a><!--a comment--><?another pi?></a>')
1498 style = self.parse('''\
1499 <xsl:stylesheet version="1.0"
1500 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1501 xmlns:myns="testns"
1502 extension-element-prefixes="myns"
1503 exclude-result-prefixes="myns">
1504 <xsl:template match="/">
1505 <ROOT><xsl:apply-templates /></ROOT>
1506 </xsl:template>
1507 <xsl:template match="comment()">
1508 <A><myns:myext>b</myns:myext></A>
1509 </xsl:template>
1510 <xsl:template match="processing-instruction()">
1511 <A><myns:myext>b</myns:myext></A>
1512 </xsl:template>
1513 </xsl:stylesheet>''')
1514
1515 text = []
1516
1517 class MyExt(etree.XSLTExtension):
1518 def execute(self, context, self_node, input_node, output_parent):
1519 text.append(input_node.text)
1520
1521 extensions = { ('testns', 'myext') : MyExt() }
1522
1523 result = tree.xslt(style, extensions=extensions)
1524 self.assertEqual(text, ['toast', 'a comment', 'pi'])
1525
1527
1528 tree = self.parse('<a test="A"><b attr="B"/></a>')
1529 style = self.parse('''\
1530 <xsl:stylesheet version="1.0"
1531 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1532 xmlns:myns="testns"
1533 extension-element-prefixes="myns"
1534 exclude-result-prefixes="myns">
1535 <xsl:template match="@test">
1536 <A><myns:myext>b</myns:myext></A>
1537 </xsl:template>
1538 <xsl:template match="@attr">
1539 <A><myns:myext>b</myns:myext></A>
1540 </xsl:template>
1541 </xsl:stylesheet>''')
1542
1543 text = []
1544
1545 class MyExt(etree.XSLTExtension):
1546 def execute(self, context, self_node, attr_value, output_parent):
1547 text.append(attr_value)
1548
1549 extensions = { ('testns', 'myext') : MyExt() }
1550
1551 result = tree.xslt(style, extensions=extensions)
1552 self.assertEqual(text, ['A', 'B'])
1553
1555 tree = self.parse('<a><b>B</b></a>')
1556 style = self.parse('''\
1557 <xsl:stylesheet version="1.0"
1558 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1559 xmlns:myns="testns"
1560 extension-element-prefixes="myns">
1561 <xsl:template match="a">
1562 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1563 </xsl:template>
1564 </xsl:stylesheet>''')
1565
1566 class MyExt(etree.XSLTExtension):
1567 def execute(self, context, self_node, input_node, output_parent):
1568 output_parent.extend(list(self_node)[1:])
1569
1570 extensions = { ('testns', 'myext') : MyExt() }
1571
1572 result = tree.xslt(style, extensions=extensions)
1573 self.assertEqual(self._rootstring(result),
1574 _bytes('<A><y>Y</y><z/></A>'))
1575
1577 tree = self.parse('<a><b>B</b></a>')
1578 style = self.parse('''\
1579 <xsl:stylesheet version="1.0"
1580 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1581 xmlns:myns="testns"
1582 extension-element-prefixes="myns">
1583 <xsl:template match="a">
1584 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1585 </xsl:template>
1586 <xsl:template match="x" />
1587 <xsl:template match="z">XYZ</xsl:template>
1588 </xsl:stylesheet>''')
1589
1590 class MyExt(etree.XSLTExtension):
1591 def execute(self, context, self_node, input_node, output_parent):
1592 for child in self_node:
1593 for result in self.apply_templates(context, child):
1594 if isinstance(result, basestring):
1595 el = etree.Element("T")
1596 el.text = result
1597 else:
1598 el = result
1599 output_parent.append(el)
1600
1601 extensions = { ('testns', 'myext') : MyExt() }
1602
1603 result = tree.xslt(style, extensions=extensions)
1604 self.assertEqual(self._rootstring(result),
1605 _bytes('<A><T>Y</T><T>XYZ</T></A>'))
1606
1608 tree = self.parse('<a><b>B</b></a>')
1609 style = self.parse('''\
1610 <xsl:stylesheet version="1.0"
1611 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1612 xmlns:myns="testns"
1613 extension-element-prefixes="myns">
1614 <xsl:template match="a">
1615 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1616 </xsl:template>
1617 <xsl:template match="x"><X/></xsl:template>
1618 <xsl:template match="z">XYZ</xsl:template>
1619 </xsl:stylesheet>''')
1620
1621 class MyExt(etree.XSLTExtension):
1622 def execute(self, context, self_node, input_node, output_parent):
1623 for child in self_node:
1624 for result in self.apply_templates(context, child,
1625 elements_only=True):
1626 assert not isinstance(result, basestring)
1627 output_parent.append(result)
1628
1629 extensions = { ('testns', 'myext') : MyExt() }
1630
1631 result = tree.xslt(style, extensions=extensions)
1632 self.assertEqual(self._rootstring(result),
1633 _bytes('<A><X/></A>'))
1634
1636 tree = self.parse('<a><b>B</b></a>')
1637 style = self.parse('''\
1638 <xsl:stylesheet version="1.0"
1639 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1640 xmlns:myns="testns"
1641 extension-element-prefixes="myns">
1642 <xsl:template match="a">
1643 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1644 </xsl:template>
1645 <xsl:template match="x"><X/></xsl:template>
1646 <xsl:template match="y"><xsl:text> </xsl:text></xsl:template>
1647 <xsl:template match="z">XYZ</xsl:template>
1648 </xsl:stylesheet>''')
1649
1650 class MyExt(etree.XSLTExtension):
1651 def execute(self, context, self_node, input_node, output_parent):
1652 for child in self_node:
1653 for result in self.apply_templates(context, child,
1654 remove_blank_text=True):
1655 if isinstance(result, basestring):
1656 assert result.strip()
1657 el = etree.Element("T")
1658 el.text = result
1659 else:
1660 el = result
1661 output_parent.append(el)
1662
1663 extensions = { ('testns', 'myext') : MyExt() }
1664
1665 result = tree.xslt(style, extensions=extensions)
1666 self.assertEqual(self._rootstring(result),
1667 _bytes('<A><X/><T>XYZ</T></A>'))
1668
1670 tree = self.parse('<a><b>B</b></a>')
1671 style = self.parse('''\
1672 <xsl:stylesheet version="1.0"
1673 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1674 xmlns:myns="testns"
1675 extension-element-prefixes="myns">
1676 <xsl:template match="a">
1677 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
1678 </xsl:template>
1679 <xsl:template match="x" />
1680 <xsl:template match="z">XYZ</xsl:template>
1681 </xsl:stylesheet>''')
1682
1683 class MyExt(etree.XSLTExtension):
1684 def execute(self, context, self_node, input_node, output_parent):
1685 for child in self_node:
1686 self.apply_templates(context, child, output_parent)
1687
1688 extensions = { ('testns', 'myext') : MyExt() }
1689
1690 result = tree.xslt(style, extensions=extensions)
1691 self.assertEqual(self._rootstring(result),
1692 _bytes('<A>YXYZ</A>'))
1693
1695 tree = self.parse('<a><b>B</b></a>')
1696 style = self.parse('''\
1697 <xsl:stylesheet version="1.0"
1698 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1699 xmlns:myns="testns"
1700 extension-element-prefixes="myns">
1701 <xsl:template match="a">
1702 <myns:myext><x>X</x><y>Y</y><z/></myns:myext>
1703 </xsl:template>
1704 <xsl:template match="x"><xsl:processing-instruction name="test">TEST</xsl:processing-instruction></xsl:template>
1705 <xsl:template match="y"><Y>XYZ</Y></xsl:template>
1706 <xsl:template match="z"><xsl:comment>TEST</xsl:comment></xsl:template>
1707 </xsl:stylesheet>''')
1708
1709 class MyExt(etree.XSLTExtension):
1710 def execute(self, context, self_node, input_node, output_parent):
1711 for child in self_node:
1712 self.apply_templates(context, child, output_parent)
1713
1714 extensions = { ('testns', 'myext') : MyExt() }
1715
1716 result = tree.xslt(style, extensions=extensions)
1717 self.assertEqual(etree.tostring(result),
1718 _bytes('<?test TEST?><Y>XYZ</Y><!--TEST-->'))
1719
1721 tree = self.parse('<a><b>E</b></a>')
1722 style = self.parse('''\
1723 <xsl:stylesheet version="1.0"
1724 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1725 xmlns:myns="testns"
1726 extension-element-prefixes="myns">
1727 <xsl:template match="a">
1728 <xsl:variable name="testvar">yo</xsl:variable>
1729 <A>
1730 <myns:myext>
1731 <xsl:attribute name="attr">
1732 <xsl:value-of select="$testvar" />
1733 </xsl:attribute>
1734 <B>
1735 <xsl:choose>
1736 <xsl:when test="1 = 2"><C/></xsl:when>
1737 <xsl:otherwise><D><xsl:value-of select="b/text()" /></D></xsl:otherwise>
1738 </xsl:choose>
1739 </B>
1740 </myns:myext>
1741 </A>
1742 </xsl:template>
1743 </xsl:stylesheet>''')
1744
1745 class MyExt(etree.XSLTExtension):
1746 def execute(self, context, self_node, input_node, output_parent):
1747 el = etree.Element('MY')
1748 self.process_children(context, el)
1749 output_parent.append(el)
1750
1751 extensions = { ('testns', 'myext') : MyExt() }
1752
1753 result = tree.xslt(style, extensions=extensions)
1754 self.assertEqual(self._rootstring(result),
1755 _bytes('<A><MYattr="yo"><B><D>E</D></B></MY></A>'))
1756
1758 tree = self.parse('<a/>')
1759 style = self.parse('''\
1760 <xsl:stylesheet version="1.0"
1761 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1762 xmlns:myns="testns"
1763 extension-element-prefixes="myns">
1764 <xsl:template match="a">
1765 <myns:myext>
1766 <A/>
1767 </myns:myext>
1768 </xsl:template>
1769 </xsl:stylesheet>''')
1770
1771 class MyExt(etree.XSLTExtension):
1772 def execute(self, context, self_node, input_node, output_parent):
1773 self.process_children(context, output_parent)
1774
1775 extensions = { ('testns', 'myext') : MyExt() }
1776
1777 result = tree.xslt(style, extensions=extensions)
1778 self.assertEqual(self._rootstring(result),
1779 _bytes('<A/>'))
1780
1782 tree = self.parse('<a/>')
1783 style = self.parse('''\
1784 <xsl:stylesheet version="1.0"
1785 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1786 xmlns:myns="testns"
1787 extension-element-prefixes="myns">
1788 <xsl:template match="a">
1789 <myns:myext>
1790 <A/>
1791 </myns:myext>
1792 </xsl:template>
1793 </xsl:stylesheet>''')
1794
1795 class MyExt(etree.XSLTExtension):
1796 def execute(self, context, self_node, input_node, output_parent):
1797 self.process_children(context, self_node)
1798
1799 extensions = { ('testns', 'myext') : MyExt() }
1800
1801 self.assertRaises(TypeError, tree.xslt, style, extensions=extensions)
1802
1804 tree = self.parse('<a/>')
1805 style = self.parse('''\
1806 <xsl:stylesheet version="1.0"
1807 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1808 xmlns:myns="testns"
1809 extension-element-prefixes="myns">
1810 <xsl:template match="a">
1811 <myns:myext>
1812 <A><myns:myext><B/></myns:myext></A>
1813 </myns:myext>
1814 </xsl:template>
1815 </xsl:stylesheet>''')
1816
1817 class MyExt(etree.XSLTExtension):
1818 callback_call_counter = 0
1819 def execute(self, context, self_node, input_node, output_parent):
1820 self.callback_call_counter += 1
1821 el = etree.Element('MY', n=str(self.callback_call_counter))
1822 self.process_children(context, el)
1823 output_parent.append(el)
1824
1825 extensions = { ('testns', 'myext') : MyExt() }
1826
1827 result = tree.xslt(style, extensions=extensions)
1828 self.assertEqual(self._rootstring(result),
1829 _bytes('<MYn="1"><A><MYn="2"><B/></MY></A></MY>'))
1830
1832 tree = self.parse('<a><b>B</b></a>')
1833 style = self.parse('''\
1834 <xsl:stylesheet version="1.0"
1835 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1836 xmlns:myns="testns"
1837 extension-element-prefixes="myns"
1838 exclude-result-prefixes="myns">
1839 <xsl:template match="a">
1840 <A><myns:myext>b</myns:myext></A>
1841 </xsl:template>
1842 </xsl:stylesheet>''')
1843
1844 class MyError(Exception):
1845 pass
1846
1847 class MyExt(etree.XSLTExtension):
1848 def execute(self, context, self_node, input_node, output_parent):
1849 raise MyError("expected!")
1850
1851 extensions = { ('testns', 'myext') : MyExt() }
1852 self.assertRaises(MyError, tree.xslt, style, extensions=extensions)
1853
1854
1855
1857 tree = self.parse("""\
1858 <text>
1859 <par>This is <format>arbitrary</format> text in a paragraph</par>
1860 </text>""")
1861 style = self.parse("""\
1862 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my" extension-element-prefixes="my" version="1.0">
1863 <xsl:template match="par">
1864 <my:par><xsl:apply-templates /></my:par>
1865 </xsl:template>
1866 <xsl:template match="format">
1867 <my:format><xsl:apply-templates /></my:format>
1868 </xsl:template>
1869 </xsl:stylesheet>
1870 """)
1871 test = self
1872 calls = []
1873
1874 class ExtMyPar(etree.XSLTExtension):
1875 def execute(self, context, self_node, input_node, output_parent):
1876 calls.append('par')
1877 p = etree.Element("p")
1878 p.attrib["style"] = "color:red"
1879 self.process_children(context, p)
1880 output_parent.append(p)
1881
1882 class ExtMyFormat(etree.XSLTExtension):
1883 def execute(self, context, self_node, input_node, output_parent):
1884 calls.append('format')
1885 content = self.process_children(context)
1886 test.assertEqual(1, len(content))
1887 test.assertEqual('arbitrary', content[0])
1888 test.assertEqual('This is ', output_parent.text)
1889 output_parent.text += '*-%s-*' % content[0]
1890
1891 extensions = {("my", "par"): ExtMyPar(), ("my", "format"): ExtMyFormat()}
1892 transform = etree.XSLT(style, extensions=extensions)
1893 result = transform(tree)
1894 self.assertEqual(['par', 'format'], calls)
1895 self.assertEqual(
1896 b'<p style="color:red">This is *-arbitrary-* text in a paragraph</p>\n',
1897 etree.tostring(result))
1898
1899
1901 """XSLT tests for etree under Python 3"""
1902
1903 pytestmark = skipif('sys.version_info < (3,0)')
1904
1906 tree = self.parse('<a><b>B</b><c>C</c></a>')
1907 style = self.parse('''\
1908 <xsl:stylesheet version="1.0"
1909 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1910 <xsl:template match="*" />
1911 <xsl:template match="/">
1912 <foo><xsl:value-of select="/a/b/text()" /></foo>
1913 </xsl:template>
1914 </xsl:stylesheet>''')
1915
1916 st = etree.XSLT(style)
1917 res = st(tree)
1918 self.assertEqual(_bytes('''\
1919 <?xml version="1.0"?>
1920 <foo>B</foo>
1921 '''),
1922 bytes(res))
1923
1925 tree = self.parse('<a><b>B</b><c>C</c></a>')
1926 style = self.parse('''\
1927 <xsl:stylesheet version="1.0"
1928 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1929 <xsl:template match="*" />
1930 <xsl:template match="/">
1931 <foo><xsl:value-of select="/a/b/text()" /></foo>
1932 </xsl:template>
1933 </xsl:stylesheet>''')
1934
1935 st = etree.XSLT(style)
1936 res = st(tree)
1937 self.assertEqual(_bytes('''\
1938 <?xml version="1.0"?>
1939 <foo>B</foo>
1940 '''),
1941 bytearray(res))
1942
1944 tree = self.parse('<a><b>B</b><c>C</c></a>')
1945 style = self.parse('''\
1946 <xsl:stylesheet version="1.0"
1947 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1948 <xsl:template match="*" />
1949 <xsl:template match="/">
1950 <foo><xsl:value-of select="/a/b/text()" /></foo>
1951 </xsl:template>
1952 </xsl:stylesheet>''')
1953
1954 st = etree.XSLT(style)
1955 res = st(tree)
1956 self.assertEqual(_bytes('''\
1957 <?xml version="1.0"?>
1958 <foo>B</foo>
1959 '''),
1960 bytes(memoryview(res)))
1961
1962
1976
1977 if __name__ == '__main__':
1978 print('to test use test.py %s' % __file__)
1979