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