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 = __builtins__["unicode"]
17 except (NameError, KeyError):
18 unicode = str
19
20 try:
21 basestring = __builtins__["basestring"]
22 except (NameError, KeyError):
23 basestring = str
24
25 from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir
26 from common_imports import doctest, _bytes, _str, make_doctest
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.assertEquals('''\
45 <?xml version="1.0"?>
46 <foo>B</foo>
47 ''',
48 str(res))
49
52
55
56 if False and etree.LIBXSLT_VERSION >= (1,1,15):
57
58 if etree.LIBXSLT_VERSION > (1,1,17):
60 style = self.parse('''\
61 <xsl:stylesheet version="1.0"
62 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
63 <xsl:stylesheet />
64 </xsl:stylesheet>''')
65
66 self.assertRaises(
67 etree.XSLTParseError, etree.XSLT, style)
68
70 tree = self.parse('<a><b>B</b><c>C</c></a>')
71 style = self.parse('''\
72 <xsl:stylesheet version="1.0"
73 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
74 <xsl:template match="*" />
75 <xsl:template match="/">
76 <foo><xsl:value-of select="/a/b/text()" /></foo>
77 </xsl:template>
78 </xsl:stylesheet>''')
79
80 transform = etree.XSLT(style)
81 res = transform(tree)
82 self.assertEquals('''\
83 <?xml version="1.0"?>
84 <foo>B</foo>
85 ''',
86 str(res))
87
88 transform_copy = copy.deepcopy(transform)
89 res = transform_copy(tree)
90 self.assertEquals('''\
91 <?xml version="1.0"?>
92 <foo>B</foo>
93 ''',
94 str(res))
95
96 transform = etree.XSLT(style)
97 res = transform(tree)
98 self.assertEquals('''\
99 <?xml version="1.0"?>
100 <foo>B</foo>
101 ''',
102 str(res))
103
105 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
106 ).decode("unicode_escape"))
107 style = self.parse('''\
108 <xsl:stylesheet version="1.0"
109 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
110 <xsl:output encoding="UTF-8"/>
111 <xsl:template match="/">
112 <foo><xsl:value-of select="/a/b/text()" /></foo>
113 </xsl:template>
114 </xsl:stylesheet>''')
115
116 st = etree.XSLT(style)
117 res = st(tree)
118 expected = _bytes('''\
119 <?xml version="1.0" encoding="UTF-8"?>
120 <foo>\\uF8D2</foo>
121 ''').decode("unicode_escape")
122 if is_python3:
123 self.assertEquals(expected,
124 str(bytes(res), 'UTF-8'))
125 else:
126 self.assertEquals(expected,
127 unicode(str(res), 'UTF-8'))
128
130 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
131 ).decode("unicode_escape"))
132 style = self.parse('''\
133 <xsl:stylesheet version="1.0"
134 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
135 <xsl:output encoding="UTF-16"/>
136 <xsl:template match="/">
137 <foo><xsl:value-of select="/a/b/text()" /></foo>
138 </xsl:template>
139 </xsl:stylesheet>''')
140
141 st = etree.XSLT(style)
142 res = st(tree)
143 expected = _bytes('''\
144 <?xml version="1.0" encoding="UTF-16"?>
145 <foo>\\uF8D2</foo>
146 ''').decode("unicode_escape")
147 if is_python3:
148 self.assertEquals(expected,
149 str(bytes(res), 'UTF-16'))
150 else:
151 self.assertEquals(expected,
152 unicode(str(res), 'UTF-16'))
153
155 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
156 ).decode("unicode_escape"))
157 style = self.parse('''\
158 <xsl:stylesheet version="1.0"
159 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
160 <xsl:output encoding="UTF-8"/>
161 <xsl:template match="/">
162 <foo><xsl:value-of select="/a/b/text()" /></foo>
163 </xsl:template>
164 </xsl:stylesheet>''')
165
166 st = etree.XSLT(style)
167 res = st(tree)
168 expected = _bytes("""\
169 <?xml version='1.0' encoding='UTF-16'?>\
170 <foo>\\uF8D2</foo>""").decode("unicode_escape")
171
172 f = BytesIO()
173 res.write(f, encoding='UTF-16')
174 if is_python3:
175 result = str(f.getvalue(), 'UTF-16').replace('\n', '')
176 else:
177 result = unicode(str(f.getvalue()), 'UTF-16').replace('\n', '')
178 self.assertEquals(expected, result)
179
181 tree = self.parse(_bytes('<a><b>\\uF8D2</b><c>\\uF8D2</c></a>'
182 ).decode("unicode_escape"))
183 style = self.parse('''\
184 <xsl:stylesheet version="1.0"
185 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
186 <xsl:output encoding="UTF-16"/>
187 <xsl:template match="/">
188 <foo><xsl:value-of select="/a/b/text()" /></foo>
189 </xsl:template>
190 </xsl:stylesheet>''')
191
192 st = etree.XSLT(style)
193 res = st(tree)
194 expected = _bytes('''\
195 <?xml version="1.0"?>
196 <foo>\\uF8D2</foo>
197 ''').decode("unicode_escape")
198 self.assertEquals(expected,
199 unicode(res))
200
202 tree = self.parse('<a><b>B</b><c>C</c></a>')
203 style = self.parse('''\
204 <xsl:stylesheet version="1.0"
205 xmlns:str="http://exslt.org/strings"
206 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
207 exclude-result-prefixes="str xsl">
208 <xsl:template match="text()">
209 <xsl:value-of select="str:align(string(.), '***', 'center')" />
210 </xsl:template>
211 <xsl:template match="*">
212 <xsl:copy>
213 <xsl:apply-templates/>
214 </xsl:copy>
215 </xsl:template>
216 </xsl:stylesheet>''')
217
218 st = etree.XSLT(style)
219 res = st(tree)
220 self.assertEquals('''\
221 <?xml version="1.0"?>
222 <a><b>*B*</b><c>*C*</c></a>
223 ''',
224 str(res))
225
226 if etree.LIBXSLT_VERSION >= (1,1,21):
228 tree = self.parse('<a><b>B</b><c>C</c></a>')
229 style = self.parse('''\
230 <xsl:stylesheet version = "1.0"
231 xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
232 xmlns:str="http://exslt.org/strings"
233 extension-element-prefixes="str">
234
235 <xsl:template match="/">
236 <h1 class="{str:replace('abc', 'b', 'x')}">test</h1>
237 </xsl:template>
238
239 </xsl:stylesheet>''')
240
241 st = etree.XSLT(style)
242 res = st(tree)
243 self.assertEquals('''\
244 <?xml version="1.0"?>
245 <h1 class="axc">test</h1>
246 ''',
247 str(res))
248
250 tree = self.parse('<a><b>B</b><c>C</c></a>')
251 style = self.parse('''\
252 <xsl:stylesheet version="1.0"
253 xmlns:math="http://exslt.org/math"
254 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
255 exclude-result-prefixes="math xsl">
256 <xsl:template match="*">
257 <xsl:copy>
258 <xsl:attribute name="pi">
259 <xsl:value-of select="math:constant('PI', count(*)+2)"/>
260 </xsl:attribute>
261 <xsl:apply-templates/>
262 </xsl:copy>
263 </xsl:template>
264 </xsl:stylesheet>''')
265
266 st = etree.XSLT(style)
267 res = st(tree)
268 self.assertEquals('''\
269 <?xml version="1.0"?>
270 <a pi="3.14"><b pi="3">B</b><c pi="3">C</c></a>
271 ''',
272 str(res))
273
286
303
305 tree = self.parse('<a/>')
306 style = self.parse('''\
307 <xsl:stylesheet version="1.0"
308 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
309 <xsl:foo />
310 </xsl:stylesheet>''')
311 self.assertRaises(etree.XSLTParseError,
312 etree.XSLT, style)
313
315 tree = self.parse('<a><b>B</b><c>C</c></a>')
316 style = self.parse('''\
317 <xsl:stylesheet version="1.0"
318 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
319 <xsl:template match="/">
320 <foo><xsl:value-of select="$bar" /></foo>
321 </xsl:template>
322 </xsl:stylesheet>''')
323
324 st = etree.XSLT(style)
325 res = st(tree, bar="'Bar'")
326 self.assertEquals('''\
327 <?xml version="1.0"?>
328 <foo>Bar</foo>
329 ''',
330 str(res))
331
333 tree = self.parse('<a><b>B</b><c>C</c></a>')
334 style = self.parse('''\
335 <xsl:stylesheet version="1.0"
336 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
337 <xsl:template match="/">
338 <foo><xsl:value-of select="$bar" /></foo>
339 </xsl:template>
340 </xsl:stylesheet>''')
341
342 st = etree.XSLT(style)
343 res = st(tree, bar=etree.XSLT.strparam('''it's me, "Bar"'''))
344 self.assertEquals('''\
345 <?xml version="1.0"?>
346 <foo>it's me, "Bar"</foo>
347 ''',
348 str(res))
349
351 tree = self.parse('<a><b>B</b><c>C</c></a>')
352 style = self.parse('''\
353 <xsl:stylesheet version="1.0"
354 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
355 <xsl:param name="bar"/>
356 <xsl:template match="/">
357 <foo><xsl:value-of select="$bar" /></foo>
358 </xsl:template>
359 </xsl:stylesheet>''')
360
361 st = etree.XSLT(style)
362 res = self.assertRaises(etree.XSLTApplyError,
363 st, tree, bar="<test/>")
364 res = self.assertRaises(etree.XSLTApplyError,
365 st, tree, bar="....")
366
367 if etree.LIBXSLT_VERSION < (1,1,18):
368
370
371 tree = self.parse('<a><b>B</b><c>C</c></a>')
372 style = self.parse('''\
373 <xsl:stylesheet version="1.0"
374 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
375 <xsl:template match="/">
376 <foo><xsl:value-of select="$bar" /></foo>
377 </xsl:template>
378 </xsl:stylesheet>''')
379
380 st = etree.XSLT(style)
381 self.assertRaises(etree.XSLTApplyError,
382 st.apply, tree)
383
385 tree = self.parse('<a><b>B</b><c>C</c></a>')
386 style = self.parse('''\
387 <xsl:stylesheet version="1.0"
388 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
389 <xsl:template match="*" />
390 <xsl:template match="/">
391 <foo><xsl:value-of select="$bar" /></foo>
392 <foo><xsl:value-of select="$baz" /></foo>
393 </xsl:template>
394 </xsl:stylesheet>''')
395
396 st = etree.XSLT(style)
397 res = st(tree, bar="'Bar'", baz="'Baz'")
398 self.assertEquals('''\
399 <?xml version="1.0"?>
400 <foo>Bar</foo><foo>Baz</foo>
401 ''',
402 str(res))
403
405 tree = self.parse('<a><b>B</b><c>C</c></a>')
406 style = self.parse('''\
407 <xsl:stylesheet version="1.0"
408 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
409 <xsl:template match="*" />
410 <xsl:template match="/">
411 <foo><xsl:value-of select="$bar" /></foo>
412 </xsl:template>
413 </xsl:stylesheet>''')
414
415 st = etree.XSLT(style)
416 res = st(tree, bar="/a/b/text()")
417 self.assertEquals('''\
418 <?xml version="1.0"?>
419 <foo>B</foo>
420 ''',
421 str(res))
422
423
425 tree = self.parse('<a><b>B</b><c>C</c></a>')
426 style = self.parse('''\
427 <xsl:stylesheet version="1.0"
428 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
429 <xsl:param name="bar" select="'Default'" />
430 <xsl:template match="*" />
431 <xsl:template match="/">
432 <foo><xsl:value-of select="$bar" /></foo>
433 </xsl:template>
434 </xsl:stylesheet>''')
435
436 st = etree.XSLT(style)
437 res = st(tree, bar="'Bar'")
438 self.assertEquals('''\
439 <?xml version="1.0"?>
440 <foo>Bar</foo>
441 ''',
442 str(res))
443 res = st(tree)
444 self.assertEquals('''\
445 <?xml version="1.0"?>
446 <foo>Default</foo>
447 ''',
448 str(res))
449
451 tree = self.parse('<a><b>B</b><c>C</c></a>')
452 style = self.parse('''\
453 <xsl:stylesheet version="1.0"
454 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
455 <xsl:output method="html"/>
456 <xsl:strip-space elements="*"/>
457 <xsl:template match="/">
458 <html><body><xsl:value-of select="/a/b/text()" /></body></html>
459 </xsl:template>
460 </xsl:stylesheet>''')
461
462 st = etree.XSLT(style)
463 res = st(tree)
464 self.assertEquals('<html><body>B</body></html>',
465 str(res).strip())
466
470
476
499
524
526
527 xml = '<blah/>'
528 xslt = '''
529 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
530 <xsl:template match="/" />
531 </xsl:stylesheet>
532 '''
533
534 source = self.parse(xml)
535 styledoc = self.parse(xslt)
536 style = etree.XSLT(styledoc)
537 result = style(source)
538 self.assertEqual('', str(result))
539
541 xml = '<blah/>'
542 xslt = '''
543 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
544 <xsl:template match="/">
545 <xsl:message>TEST TEST TEST</xsl:message>
546 </xsl:template>
547 </xsl:stylesheet>
548 '''
549
550 source = self.parse(xml)
551 styledoc = self.parse(xslt)
552 style = etree.XSLT(styledoc)
553 result = style(source)
554 self.assertEqual('', str(result))
555 self.assert_("TEST TEST TEST" in [entry.message
556 for entry in style.error_log])
557
559 xml = '<blah/>'
560 xslt = '''
561 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
562 <xsl:template match="/">
563 <xsl:message terminate="yes">TEST TEST TEST</xsl:message>
564 </xsl:template>
565 </xsl:stylesheet>
566 '''
567
568 source = self.parse(xml)
569 styledoc = self.parse(xslt)
570 style = etree.XSLT(styledoc)
571
572 self.assertRaises(etree.XSLTApplyError, style, source)
573 self.assert_("TEST TEST TEST" in [entry.message
574 for entry in style.error_log])
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="*" />
582 <xsl:template match="/">
583 <doc>
584 <foo><xsl:value-of select="$bar" /></foo>
585 <foo><xsl:value-of select="$baz" /></foo>
586 </doc>
587 </xsl:template>
588 </xsl:stylesheet>''')
589
590 result = tree.xslt(style, bar="'Bar'", baz="'Baz'")
591 self.assertEquals(
592 _bytes('<doc><foo>Bar</foo><foo>Baz</foo></doc>'),
593 etree.tostring(result.getroot()))
594
596 tree = self.parse('<a><b>B</b><c>C</c></a>')
597 style = self.parse('''\
598 <xsl:stylesheet version="1.0"
599 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
600 <xsl:template match="a"><A><xsl:apply-templates/></A></xsl:template>
601 <xsl:template match="b"><B><xsl:apply-templates/></B></xsl:template>
602 <xsl:template match="c"><C><xsl:apply-templates/></C></xsl:template>
603 </xsl:stylesheet>''')
604
605 self.assertEquals(self._rootstring(tree),
606 _bytes('<a><b>B</b><c>C</c></a>'))
607 result = tree.xslt(style)
608 self.assertEquals(self._rootstring(tree),
609 _bytes('<a><b>B</b><c>C</c></a>'))
610 self.assertEquals(self._rootstring(result),
611 _bytes('<A><B>B</B><C>C</C></A>'))
612
613 b_tree = etree.ElementTree(tree.getroot()[0])
614 self.assertEquals(self._rootstring(b_tree),
615 _bytes('<b>B</b>'))
616 result = b_tree.xslt(style)
617 self.assertEquals(self._rootstring(tree),
618 _bytes('<a><b>B</b><c>C</c></a>'))
619 self.assertEquals(self._rootstring(result),
620 _bytes('<B>B</B>'))
621
622 c_tree = etree.ElementTree(tree.getroot()[1])
623 self.assertEquals(self._rootstring(c_tree),
624 _bytes('<c>C</c>'))
625 result = c_tree.xslt(style)
626 self.assertEquals(self._rootstring(tree),
627 _bytes('<a><b>B</b><c>C</c></a>'))
628 self.assertEquals(self._rootstring(result),
629 _bytes('<C>C</C>'))
630
632 tree = self.parse('<a><b>B</b></a>')
633 style = self.parse('''\
634 <xsl:stylesheet version="1.0"
635 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
636 xmlns:myns="testns"
637 exclude-result-prefixes="myns">
638 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
639 </xsl:stylesheet>''')
640
641 def mytext(ctxt, values):
642 return 'X' * len(values)
643
644 result = tree.xslt(style, {('testns', 'mytext') : mytext})
645 self.assertEquals(self._rootstring(result),
646 _bytes('<A>X</A>'))
647
649 tree = self.parse('<a><b>B</b></a>')
650 style = self.parse('''\
651 <xsl:stylesheet version="1.0"
652 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
653 xmlns:myns="testns"
654 exclude-result-prefixes="myns">
655 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
656 </xsl:stylesheet>''')
657
658 def mytext(ctxt, values):
659 return 'X' * len(values)
660
661 namespace = etree.FunctionNamespace('testns')
662 namespace['mytext'] = mytext
663
664 result = tree.xslt(style)
665 self.assertEquals(self._rootstring(result),
666 _bytes('<A>X</A>'))
667
669 tree = self.parse('<a><b>B</b><b/></a>')
670 style = self.parse('''\
671 <xsl:stylesheet version="1.0"
672 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
673 xmlns:myns="testns"
674 exclude-result-prefixes="myns">
675 <xsl:template match="a">
676 <xsl:variable name="content">
677 <xsl:apply-templates/>
678 </xsl:variable>
679 <A><xsl:value-of select="myns:mytext($content)"/></A>
680 </xsl:template>
681 <xsl:template match="b"><xsl:copy>BBB</xsl:copy></xsl:template>
682 </xsl:stylesheet>''')
683
684 def mytext(ctxt, values):
685 for value in values:
686 self.assert_(hasattr(value, 'tag'),
687 "%s is not an Element" % type(value))
688 self.assertEquals(value.tag, 'b')
689 self.assertEquals(value.text, 'BBB')
690 return 'X'.join([el.tag for el in values])
691
692 namespace = etree.FunctionNamespace('testns')
693 namespace['mytext'] = mytext
694
695 result = tree.xslt(style)
696 self.assertEquals(self._rootstring(result),
697 _bytes('<A>bXb</A>'))
698
700 tree = self.parse('<a><b>B</b></a>')
701 style = self.parse('''\
702 <xsl:stylesheet version="1.0"
703 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
704 xmlns:myns="testns"
705 extension-element-prefixes="myns"
706 exclude-result-prefixes="myns">
707 <xsl:template match="a">
708 <A><myns:myext>b</myns:myext></A>
709 </xsl:template>
710 </xsl:stylesheet>''')
711
712 class MyExt(etree.XSLTExtension):
713 def execute(self, context, self_node, input_node, output_parent):
714 child = etree.Element(self_node.text)
715 child.text = 'X'
716 output_parent.append(child)
717
718 extensions = { ('testns', 'myext') : MyExt() }
719
720 result = tree.xslt(style, extensions=extensions)
721 self.assertEquals(self._rootstring(result),
722 _bytes('<A><b>X</b></A>'))
723
725 tree = self.parse('<a><b>B</b></a>')
726 style = self.parse('''\
727 <xsl:stylesheet version="1.0"
728 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
729 xmlns:myns="testns"
730 extension-element-prefixes="myns">
731 <xsl:template match="a">
732 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
733 </xsl:template>
734 </xsl:stylesheet>''')
735
736 class MyExt(etree.XSLTExtension):
737 def execute(self, context, self_node, input_node, output_parent):
738 output_parent.extend(list(self_node)[1:])
739
740 extensions = { ('testns', 'myext') : MyExt() }
741
742 result = tree.xslt(style, extensions=extensions)
743 self.assertEquals(self._rootstring(result),
744 _bytes('<A><y>Y</y><z/></A>'))
745
747 tree = self.parse('<a><b>B</b></a>')
748 style = self.parse('''\
749 <xsl:stylesheet version="1.0"
750 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
751 xmlns:myns="testns"
752 extension-element-prefixes="myns">
753 <xsl:template match="a">
754 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
755 </xsl:template>
756 <xsl:template match="x" />
757 <xsl:template match="z">XYZ</xsl:template>
758 </xsl:stylesheet>''')
759
760 class MyExt(etree.XSLTExtension):
761 def execute(self, context, self_node, input_node, output_parent):
762 for child in self_node:
763 for result in self.apply_templates(context, child):
764 if isinstance(result, basestring):
765 el = etree.Element("T")
766 el.text = result
767 else:
768 el = result
769 output_parent.append(el)
770
771 extensions = { ('testns', 'myext') : MyExt() }
772
773 result = tree.xslt(style, extensions=extensions)
774 self.assertEquals(self._rootstring(result),
775 _bytes('<A><T>Y</T><T>XYZ</T></A>'))
776
778 tree = self.parse('<a><b>B</b></a>')
779 style = self.parse('''\
780 <xsl:stylesheet version="1.0"
781 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
782 xmlns:myns="testns"
783 extension-element-prefixes="myns"
784 exclude-result-prefixes="myns">
785 <xsl:template match="a">
786 <A><myns:myext>b</myns:myext></A>
787 </xsl:template>
788 </xsl:stylesheet>''')
789
790 class MyError(Exception):
791 pass
792
793 class MyExt(etree.XSLTExtension):
794 def execute(self, context, self_node, input_node, output_parent):
795 raise MyError("expected!")
796
797 extensions = { ('testns', 'myext') : MyExt() }
798 self.assertRaises(MyError, tree.xslt, style, extensions=extensions)
799
801
802 xslt = etree.XSLT(etree.XML("""\
803 <xsl:stylesheet version="1.0"
804 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
805 <xsl:template match="/">
806 <test>TEXT<xsl:copy-of select="document('')//test"/></test>
807 </xsl:template>
808 </xsl:stylesheet>
809 """))
810 result = xslt(etree.XML('<a/>'))
811 root = result.getroot()
812 self.assertEquals(root.tag,
813 'test')
814 self.assertEquals(root[0].tag,
815 'test')
816 self.assertEquals(root[0].text,
817 'TEXT')
818 self.assertEquals(root[0][0].tag,
819 '{http://www.w3.org/1999/XSL/Transform}copy-of')
820
830
840
842 xslt = etree.XSLT(etree.XML("""\
843 <xsl:stylesheet version="1.0"
844 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
845 <xsl:template match="/">
846 <test>TEXT<xsl:copy-of select="document('uri:__junkfood__is__evil__')//test"/></test>
847 </xsl:template>
848 </xsl:stylesheet>
849 """))
850 self.assertRaises(etree.XSLTApplyError, xslt, etree.XML('<a/>'))
851
853
854 assertEquals = self.assertEquals
855 called = {'count' : 0}
856 class TestResolver(etree.Resolver):
857 def resolve(self, url, id, context):
858 assertEquals(url, 'file://ANYTHING')
859 called['count'] += 1
860 return self.resolve_string('<CALLED/>', context)
861
862 parser = etree.XMLParser()
863 parser.resolvers.add(TestResolver())
864
865 xslt = etree.XSLT(etree.XML(_bytes("""\
866 <xsl:stylesheet version="1.0"
867 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
868 xmlns:l="local">
869 <xsl:template match="/">
870 <test>
871 <xsl:for-each select="document('')//l:data/l:entry">
872 <xsl:copy-of select="document('file://ANYTHING')"/>
873 <xsl:copy>
874 <xsl:attribute name="value">
875 <xsl:value-of select="."/>
876 </xsl:attribute>
877 </xsl:copy>
878 </xsl:for-each>
879 </test>
880 </xsl:template>
881 <l:data>
882 <l:entry>A</l:entry>
883 <l:entry>B</l:entry>
884 </l:data>
885 </xsl:stylesheet>
886 """), parser))
887
888 self.assertEquals(called['count'], 0)
889 result = xslt(etree.XML('<a/>'))
890 self.assertEquals(called['count'], 1)
891
892 root = result.getroot()
893 self.assertEquals(root.tag,
894 'test')
895 self.assertEquals(len(root), 4)
896
897 self.assertEquals(root[0].tag,
898 'CALLED')
899 self.assertEquals(root[1].tag,
900 '{local}entry')
901 self.assertEquals(root[1].text,
902 None)
903 self.assertEquals(root[1].get("value"),
904 'A')
905 self.assertEquals(root[2].tag,
906 'CALLED')
907 self.assertEquals(root[3].tag,
908 '{local}entry')
909 self.assertEquals(root[3].text,
910 None)
911 self.assertEquals(root[3].get("value"),
912 'B')
913
915 assertEquals = self.assertEquals
916 called = {'count' : 0}
917 expected_url = None
918 class TestResolver(etree.Resolver):
919 def resolve(self, url, id, context):
920 assertEquals(url, expected_url)
921 called['count'] += 1
922 return self.resolve_string('<CALLED/>', context)
923
924 stylesheet_xml = _bytes("""\
925 <xsl:stylesheet version="1.0"
926 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
927 xmlns:l="local">
928 <xsl:template match="/">
929 <xsl:copy-of select="document('test.xml')"/>
930 </xsl:template>
931 </xsl:stylesheet>
932 """)
933
934 parser = etree.XMLParser()
935 parser.resolvers.add(TestResolver())
936
937
938 expected_url = 'test.xml'
939 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser))
940
941 self.assertEquals(called['count'], 0)
942 result = xslt(etree.XML('<a/>'))
943 self.assertEquals(called['count'], 1)
944
945
946 called['count'] = 0
947 expected_url = os.path.join('MY', 'BASE', 'test.xml')
948 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser,
949 base_url=os.path.join('MY', 'BASE', 'FILE')))
950
951 self.assertEquals(called['count'], 0)
952 result = xslt(etree.XML('<a/>'))
953 self.assertEquals(called['count'], 1)
954
955
956 called['count'] = 0
957 expected_url = 'http://server.com/BASE/DIR/test.xml'
958 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser,
959 base_url='http://server.com/BASE/DIR/FILE'))
960
961 self.assertEquals(called['count'], 0)
962 result = xslt(etree.XML('<a/>'))
963 self.assertEquals(called['count'], 1)
964
975
981
987
989 root = etree.XML(_bytes('''\
990 <transform>
991 <widget displayType="fieldset"/>
992 </transform>'''))
993
994 xslt = etree.XSLT(etree.XML(_bytes('''\
995 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
996 <xsl:output method="html" indent="no"/>
997 <xsl:template match="/">
998 <html>
999 <xsl:apply-templates/>
1000 </html>
1001 </xsl:template>
1002
1003 <xsl:template match="widget">
1004 <xsl:element name="{@displayType}"/>
1005 </xsl:template>
1006
1007 </xsl:stylesheet>''')))
1008
1009 result = xslt(root[0])
1010 root[:] = result.getroot()[:]
1011 del root
1012
1014 tree = self.parse('''\
1015 <?xml version="1.0"?>
1016 <?xml-stylesheet type="text/xsl" href="%s"?>
1017 <a>
1018 <b>B</b>
1019 <c>C</c>
1020 </a>''' % fileInTestDir("test1.xslt"))
1021
1022 style_root = tree.getroot().getprevious().parseXSL().getroot()
1023 self.assertEquals("{http://www.w3.org/1999/XSL/Transform}stylesheet",
1024 style_root.tag)
1025
1027
1028 tree = self.parse('''\
1029 <?xml version="1.0"?>
1030 <?xml-stylesheet type="text/xsl" href="#style"?>
1031 <a>
1032 <b>B</b>
1033 <c>C</c>
1034 <xsl:stylesheet version="1.0" xml:id="style"
1035 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1036 <xsl:template match="*" />
1037 <xsl:template match="/">
1038 <foo><xsl:value-of select="/a/b/text()" /></foo>
1039 </xsl:template>
1040 </xsl:stylesheet>
1041 </a>''')
1042
1043 style_root = tree.getroot().getprevious().parseXSL().getroot()
1044 self.assertEquals("{http://www.w3.org/1999/XSL/Transform}stylesheet",
1045 style_root.tag)
1046
1047 st = etree.XSLT(style_root)
1048 res = st(tree)
1049 self.assertEquals('''\
1050 <?xml version="1.0"?>
1051 <foo>B</foo>
1052 ''',
1053 str(res))
1054
1056
1057 tree = self.parse('''\
1058 <?xml version="1.0"?>
1059 <?xml-stylesheet type="text/xsl" href="#style"?>
1060 <a>
1061 <b>B</b>
1062 <c>C</c>
1063 </a>''')
1064
1065 style = self.parse('''\
1066 <xsl:stylesheet version="1.0" xml:id="style"
1067 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1068 <xsl:template match="*" />
1069 <xsl:template match="/">
1070 <foo><xsl:value-of select="/a/b/text()" /></foo>
1071 </xsl:template>
1072 </xsl:stylesheet>
1073 ''')
1074
1075 tree.getroot().append(style.getroot())
1076
1077 style_root = tree.getroot().getprevious().parseXSL().getroot()
1078 self.assertEquals("{http://www.w3.org/1999/XSL/Transform}stylesheet",
1079 style_root.tag)
1080
1081 st = etree.XSLT(style_root)
1082 res = st(tree)
1083 self.assertEquals('''\
1084 <?xml version="1.0"?>
1085 <foo>B</foo>
1086 ''',
1087 str(res))
1088
1090 tree = self.parse('''\
1091 <?xml version="1.0"?>
1092 <?xml-stylesheet type="text/xsl" href="TEST"?>
1093 <a>
1094 <b>B</b>
1095 <c>C</c>
1096 </a>''')
1097
1098 pi = tree.getroot().getprevious()
1099 self.assertEquals("TEST", pi.get("href"))
1100
1102 tree = self.parse('''\
1103 <?xml version="1.0"?>
1104 <?xml-stylesheet type="text/xsl" href="TEST"?>
1105 <a>
1106 <b>B</b>
1107 <c>C</c>
1108 </a>''')
1109
1110 pi = tree.getroot().getprevious()
1111 self.assertEquals("TEST", pi.get("href"))
1112 self.assertEquals("text/xsl", pi.get("type"))
1113 self.assertEquals(None, pi.get("motz"))
1114
1116 tree = self.parse('''\
1117 <?xml version="1.0"?>
1118 <?xml-stylesheet href="TEST" type="text/xsl"?>
1119 <a>
1120 <b>B</b>
1121 <c>C</c>
1122 </a>''')
1123
1124 pi = tree.getroot().getprevious()
1125 self.assertEquals("TEST", pi.get("href"))
1126 self.assertEquals("text/xsl", pi.get("type"))
1127 self.assertEquals(None, pi.get("motz"))
1128
1130 tree = self.parse('''\
1131 <?xml version="1.0"?>
1132 <?xml-stylesheet type="text/xsl" href="TEST"?>
1133 <a>
1134 <b>B</b>
1135 <c>C</c>
1136 </a>''')
1137
1138 pi = tree.getroot().getprevious()
1139 self.assertEquals(None, pi.get("unknownattribute"))
1140
1142 tree = self.parse('''\
1143 <?xml version="1.0"?>
1144 <?xml-stylesheet type="text/xsl" href="TEST"?>
1145 <a>
1146 <b>B</b>
1147 <c>C</c>
1148 </a>''')
1149
1150 pi = tree.getroot().getprevious()
1151 self.assertEquals("TEST", pi.get("href"))
1152
1153 pi.set("href", "TEST123")
1154 self.assertEquals("TEST123", pi.get("href"))
1155
1157 tree = self.parse('''\
1158 <?xml version="1.0"?>
1159 <?xml-stylesheet type="text/xsl"?>
1160 <a>
1161 <b>B</b>
1162 <c>C</c>
1163 </a>''')
1164
1165 pi = tree.getroot().getprevious()
1166 self.assertEquals(None, pi.get("href"))
1167
1168 pi.set("href", "TEST")
1169 self.assertEquals("TEST", pi.get("href"))
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><xsl:copy-of select="*[regexp:test(string(.), '8.')]"/></test>
1178 </xsl:template>
1179 </xsl:stylesheet>
1180 """)))
1181 result = xslt(etree.XML(_bytes('<a><b>123</b><b>098</b><b>987</b></a>')))
1182 root = result.getroot()
1183 self.assertEquals(root.tag,
1184 'test')
1185 self.assertEquals(len(root), 1)
1186 self.assertEquals(root[0].tag,
1187 'b')
1188 self.assertEquals(root[0].text,
1189 '987')
1190
1192 xslt = etree.XSLT(etree.XML("""\
1193 <xsl:stylesheet version="1.0"
1194 xmlns:regexp="http://exslt.org/regular-expressions"
1195 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1196 <xsl:template match="*">
1197 <test>
1198 <xsl:copy-of select="regexp:replace(string(.), 'd.', '', 'XX')"/>
1199 <xsl:text>-</xsl:text>
1200 <xsl:copy-of select="regexp:replace(string(.), 'd.', 'gi', 'XX')"/>
1201 </test>
1202 </xsl:template>
1203 </xsl:stylesheet>
1204 """))
1205 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1206 root = result.getroot()
1207 self.assertEquals(root.tag,
1208 'test')
1209 self.assertEquals(len(root), 0)
1210 self.assertEquals(root.text, 'abXXdEeDed-abXXXXeXXd')
1211
1213 xslt = etree.XSLT(etree.XML("""\
1214 <xsl:stylesheet version="1.0"
1215 xmlns:regexp="http://exslt.org/regular-expressions"
1216 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1217 <xsl:template match="*">
1218 <test>
1219 <test1><xsl:copy-of select="regexp:match(string(.), 'd.')"/></test1>
1220 <test2><xsl:copy-of select="regexp:match(string(.), 'd.', 'g')"/></test2>
1221 <test2i><xsl:copy-of select="regexp:match(string(.), 'd.', 'gi')"/></test2i>
1222 </test>
1223 </xsl:template>
1224 </xsl:stylesheet>
1225 """))
1226 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1227 root = result.getroot()
1228 self.assertEquals(root.tag, 'test')
1229 self.assertEquals(len(root), 3)
1230
1231 self.assertEquals(len(root[0]), 1)
1232 self.assertEquals(root[0][0].tag, 'match')
1233 self.assertEquals(root[0][0].text, 'dC')
1234
1235 self.assertEquals(len(root[1]), 2)
1236 self.assertEquals(root[1][0].tag, 'match')
1237 self.assertEquals(root[1][0].text, 'dC')
1238 self.assertEquals(root[1][1].tag, 'match')
1239 self.assertEquals(root[1][1].text, 'dE')
1240
1241 self.assertEquals(len(root[2]), 3)
1242 self.assertEquals(root[2][0].tag, 'match')
1243 self.assertEquals(root[2][0].text, 'dC')
1244 self.assertEquals(root[2][1].tag, 'match')
1245 self.assertEquals(root[2][1].text, 'dE')
1246 self.assertEquals(root[2][2].tag, 'match')
1247 self.assertEquals(root[2][2].text, 'De')
1248
1250 xslt = etree.XSLT(etree.XML(_bytes("""\
1251 <xsl:stylesheet version="1.0"
1252 xmlns:regexp="http://exslt.org/regular-expressions"
1253 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1254 <xsl:template match="/">
1255 <test>
1256 <xsl:for-each select="regexp:match(
1257 '123abc567', '([0-9]+)([a-z]+)([0-9]+)' )">
1258 <test1><xsl:value-of select="."/></test1>
1259 </xsl:for-each>
1260 </test>
1261 </xsl:template>
1262 </xsl:stylesheet>
1263 """)))
1264 result = xslt(etree.XML(_bytes('<a/>')))
1265 root = result.getroot()
1266 self.assertEquals(root.tag, 'test')
1267 self.assertEquals(len(root), 4)
1268
1269 self.assertEquals(root[0].text, "123abc567")
1270 self.assertEquals(root[1].text, "123")
1271 self.assertEquals(root[2].text, "abc")
1272 self.assertEquals(root[3].text, "567")
1273
1275
1276 xslt = etree.XSLT(etree.XML(_bytes("""\
1277 <xsl:stylesheet version="1.0"
1278 xmlns:regexp="http://exslt.org/regular-expressions"
1279 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1280 <xsl:template match="/">
1281 <test>
1282 <xsl:for-each select="regexp:match(
1283 'http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml',
1284 '(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)')">
1285 <test1><xsl:value-of select="."/></test1>
1286 </xsl:for-each>
1287 </test>
1288 </xsl:template>
1289 </xsl:stylesheet>
1290 """)))
1291 result = xslt(etree.XML(_bytes('<a/>')))
1292 root = result.getroot()
1293 self.assertEquals(root.tag, 'test')
1294 self.assertEquals(len(root), 5)
1295
1296 self.assertEquals(
1297 root[0].text,
1298 "http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml")
1299 self.assertEquals(
1300 root[1].text,
1301 "http")
1302 self.assertEquals(
1303 root[2].text,
1304 "www.bayes.co.uk")
1305 self.assertFalse(root[3].text)
1306 self.assertEquals(
1307 root[4].text,
1308 "/xml/index.xml?/xml/utils/rechecker.xml")
1309
1311
1312 xslt = etree.XSLT(self.parse("""\
1313 <xsl:stylesheet version="1.0"
1314 xmlns:regexp="http://exslt.org/regular-expressions"
1315 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1316 <xsl:template match="/">
1317 <test>
1318 <xsl:for-each select="regexp:match(
1319 'This is a test string', '(\w+)', 'g')">
1320 <test1><xsl:value-of select="."/></test1>
1321 </xsl:for-each>
1322 </test>
1323 </xsl:template>
1324 </xsl:stylesheet>
1325 """))
1326 result = xslt(etree.XML(_bytes('<a/>')))
1327 root = result.getroot()
1328 self.assertEquals(root.tag, 'test')
1329 self.assertEquals(len(root), 5)
1330
1331 self.assertEquals(root[0].text, "This")
1332 self.assertEquals(root[1].text, "is")
1333 self.assertEquals(root[2].text, "a")
1334 self.assertEquals(root[3].text, "test")
1335 self.assertEquals(root[4].text, "string")
1336
1338
1339
1340 xslt = etree.XSLT(etree.XML(_bytes("""\
1341 <xsl:stylesheet version="1.0"
1342 xmlns:regexp="http://exslt.org/regular-expressions"
1343 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1344 <xsl:template match="/">
1345 <test>
1346 <xsl:for-each select="regexp:match(
1347 'This is a test string', '([a-z])+ ', 'g')">
1348 <test1><xsl:value-of select="."/></test1>
1349 </xsl:for-each>
1350 </test>
1351 </xsl:template>
1352 </xsl:stylesheet>
1353 """)))
1354 result = xslt(etree.XML(_bytes('<a/>')))
1355 root = result.getroot()
1356 self.assertEquals(root.tag, 'test')
1357 self.assertEquals(len(root), 4)
1358
1359 self.assertEquals(root[0].text, "his")
1360 self.assertEquals(root[1].text, "is")
1361 self.assertEquals(root[2].text, "a")
1362 self.assertEquals(root[3].text, "test")
1363
1365
1366
1367 xslt = etree.XSLT(etree.XML(_bytes("""\
1368 <xsl:stylesheet version="1.0"
1369 xmlns:regexp="http://exslt.org/regular-expressions"
1370 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1371 <xsl:template match="/">
1372 <test>
1373 <xsl:for-each select="regexp:match(
1374 'This is a test string', '([a-z])+ ', 'gi')">
1375 <test1><xsl:value-of select="."/></test1>
1376 </xsl:for-each>
1377 </test>
1378 </xsl:template>
1379 </xsl:stylesheet>
1380 """)))
1381 result = xslt(etree.XML(_bytes('<a/>')))
1382 root = result.getroot()
1383 self.assertEquals(root.tag, 'test')
1384 self.assertEquals(len(root), 4)
1385
1386 self.assertEquals(root[0].text, "This")
1387 self.assertEquals(root[1].text, "is")
1388 self.assertEquals(root[2].text, "a")
1389 self.assertEquals(root[3].text, "test")
1390
1391
1393 """XSLT tests for etree under Python 3"""
1395 tree = self.parse('<a><b>B</b><c>C</c></a>')
1396 style = self.parse('''\
1397 <xsl:stylesheet version="1.0"
1398 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1399 <xsl:template match="*" />
1400 <xsl:template match="/">
1401 <foo><xsl:value-of select="/a/b/text()" /></foo>
1402 </xsl:template>
1403 </xsl:stylesheet>''')
1404
1405 st = etree.XSLT(style)
1406 res = st(tree)
1407 self.assertEquals(_bytes('''\
1408 <?xml version="1.0"?>
1409 <foo>B</foo>
1410 '''),
1411 bytes(res))
1412
1414 tree = self.parse('<a><b>B</b><c>C</c></a>')
1415 style = self.parse('''\
1416 <xsl:stylesheet version="1.0"
1417 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1418 <xsl:template match="*" />
1419 <xsl:template match="/">
1420 <foo><xsl:value-of select="/a/b/text()" /></foo>
1421 </xsl:template>
1422 </xsl:stylesheet>''')
1423
1424 st = etree.XSLT(style)
1425 res = st(tree)
1426 self.assertEquals(_bytes('''\
1427 <?xml version="1.0"?>
1428 <foo>B</foo>
1429 '''),
1430 bytearray(res))
1431
1433 tree = self.parse('<a><b>B</b><c>C</c></a>')
1434 style = self.parse('''\
1435 <xsl:stylesheet version="1.0"
1436 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1437 <xsl:template match="*" />
1438 <xsl:template match="/">
1439 <foo><xsl:value-of select="/a/b/text()" /></foo>
1440 </xsl:template>
1441 </xsl:stylesheet>''')
1442
1443 st = etree.XSLT(style)
1444 res = st(tree)
1445 self.assertEquals(_bytes('''\
1446 <?xml version="1.0"?>
1447 <foo>B</foo>
1448 '''),
1449 bytes(memoryview(res)))
1450
1451
1453 suite = unittest.TestSuite()
1454 suite.addTests([unittest.makeSuite(ETreeXSLTTestCase)])
1455 if is_python3:
1456 suite.addTests([unittest.makeSuite(Py3XSLTTestCase)])
1457 suite.addTests(
1458 [make_doctest('../../../doc/extensions.txt')])
1459 suite.addTests(
1460 [make_doctest('../../../doc/xpathxslt.txt')])
1461 return suite
1462
1463 if __name__ == '__main__':
1464 print('to test use test.py %s' % __file__)
1465