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:param name="bar"/>
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 res = self.assertRaises(etree.XSLTApplyError,
345 st, tree, bar="<test/>")
346 res = self.assertRaises(etree.XSLTApplyError,
347 st, tree, bar="....")
348
349 if etree.LIBXSLT_VERSION < (1,1,18):
350
352
353 tree = self.parse('<a><b>B</b><c>C</c></a>')
354 style = self.parse('''\
355 <xsl:stylesheet version="1.0"
356 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
357 <xsl:template match="/">
358 <foo><xsl:value-of select="$bar" /></foo>
359 </xsl:template>
360 </xsl:stylesheet>''')
361
362 st = etree.XSLT(style)
363 self.assertRaises(etree.XSLTApplyError,
364 st.apply, tree)
365
367 tree = self.parse('<a><b>B</b><c>C</c></a>')
368 style = self.parse('''\
369 <xsl:stylesheet version="1.0"
370 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
371 <xsl:template match="*" />
372 <xsl:template match="/">
373 <foo><xsl:value-of select="$bar" /></foo>
374 <foo><xsl:value-of select="$baz" /></foo>
375 </xsl:template>
376 </xsl:stylesheet>''')
377
378 st = etree.XSLT(style)
379 res = st(tree, bar="'Bar'", baz="'Baz'")
380 self.assertEquals('''\
381 <?xml version="1.0"?>
382 <foo>Bar</foo><foo>Baz</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="/a/b/text()")
399 self.assertEquals('''\
400 <?xml version="1.0"?>
401 <foo>B</foo>
402 ''',
403 str(res))
404
405
407 tree = self.parse('<a><b>B</b><c>C</c></a>')
408 style = self.parse('''\
409 <xsl:stylesheet version="1.0"
410 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
411 <xsl:param name="bar" select="'Default'" />
412 <xsl:template match="*" />
413 <xsl:template match="/">
414 <foo><xsl:value-of select="$bar" /></foo>
415 </xsl:template>
416 </xsl:stylesheet>''')
417
418 st = etree.XSLT(style)
419 res = st(tree, bar="'Bar'")
420 self.assertEquals('''\
421 <?xml version="1.0"?>
422 <foo>Bar</foo>
423 ''',
424 str(res))
425 res = st(tree)
426 self.assertEquals('''\
427 <?xml version="1.0"?>
428 <foo>Default</foo>
429 ''',
430 str(res))
431
433 tree = self.parse('<a><b>B</b><c>C</c></a>')
434 style = self.parse('''\
435 <xsl:stylesheet version="1.0"
436 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
437 <xsl:output method="html"/>
438 <xsl:strip-space elements="*"/>
439 <xsl:template match="/">
440 <html><body><xsl:value-of select="/a/b/text()" /></body></html>
441 </xsl:template>
442 </xsl:stylesheet>''')
443
444 st = etree.XSLT(style)
445 res = st(tree)
446 self.assertEquals('<html><body>B</body></html>',
447 str(res).strip())
448
452
458
481
506
508
509 xml = '<blah/>'
510 xslt = '''
511 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
512 <xsl:template match="/" />
513 </xsl:stylesheet>
514 '''
515
516 source = self.parse(xml)
517 styledoc = self.parse(xslt)
518 style = etree.XSLT(styledoc)
519 result = style(source)
520 self.assertEqual('', str(result))
521
523 xml = '<blah/>'
524 xslt = '''
525 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
526 <xsl:template match="/">
527 <xsl:message>TEST TEST TEST</xsl:message>
528 </xsl:template>
529 </xsl:stylesheet>
530 '''
531
532 source = self.parse(xml)
533 styledoc = self.parse(xslt)
534 style = etree.XSLT(styledoc)
535 result = style(source)
536 self.assertEqual('', str(result))
537 self.assert_("TEST TEST TEST" in [entry.message
538 for entry in style.error_log])
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 terminate="yes">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
554 self.assertRaises(etree.XSLTApplyError, style, source)
555 self.assert_("TEST TEST TEST" in [entry.message
556 for entry in style.error_log])
557
559 tree = self.parse('<a><b>B</b><c>C</c></a>')
560 style = self.parse('''\
561 <xsl:stylesheet version="1.0"
562 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
563 <xsl:template match="*" />
564 <xsl:template match="/">
565 <doc>
566 <foo><xsl:value-of select="$bar" /></foo>
567 <foo><xsl:value-of select="$baz" /></foo>
568 </doc>
569 </xsl:template>
570 </xsl:stylesheet>''')
571
572 result = tree.xslt(style, bar="'Bar'", baz="'Baz'")
573 self.assertEquals(
574 _bytes('<doc><foo>Bar</foo><foo>Baz</foo></doc>'),
575 etree.tostring(result.getroot()))
576
578 tree = self.parse('<a><b>B</b><c>C</c></a>')
579 style = self.parse('''\
580 <xsl:stylesheet version="1.0"
581 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
582 <xsl:template match="a"><A><xsl:apply-templates/></A></xsl:template>
583 <xsl:template match="b"><B><xsl:apply-templates/></B></xsl:template>
584 <xsl:template match="c"><C><xsl:apply-templates/></C></xsl:template>
585 </xsl:stylesheet>''')
586
587 self.assertEquals(self._rootstring(tree),
588 _bytes('<a><b>B</b><c>C</c></a>'))
589 result = tree.xslt(style)
590 self.assertEquals(self._rootstring(tree),
591 _bytes('<a><b>B</b><c>C</c></a>'))
592 self.assertEquals(self._rootstring(result),
593 _bytes('<A><B>B</B><C>C</C></A>'))
594
595 b_tree = etree.ElementTree(tree.getroot()[0])
596 self.assertEquals(self._rootstring(b_tree),
597 _bytes('<b>B</b>'))
598 result = b_tree.xslt(style)
599 self.assertEquals(self._rootstring(tree),
600 _bytes('<a><b>B</b><c>C</c></a>'))
601 self.assertEquals(self._rootstring(result),
602 _bytes('<B>B</B>'))
603
604 c_tree = etree.ElementTree(tree.getroot()[1])
605 self.assertEquals(self._rootstring(c_tree),
606 _bytes('<c>C</c>'))
607 result = c_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('<C>C</C>'))
612
614 tree = self.parse('<a><b>B</b></a>')
615 style = self.parse('''\
616 <xsl:stylesheet version="1.0"
617 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
618 xmlns:myns="testns"
619 exclude-result-prefixes="myns">
620 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
621 </xsl:stylesheet>''')
622
623 def mytext(ctxt, values):
624 return 'X' * len(values)
625
626 result = tree.xslt(style, {('testns', 'mytext') : mytext})
627 self.assertEquals(self._rootstring(result),
628 _bytes('<A>X</A>'))
629
631 tree = self.parse('<a><b>B</b></a>')
632 style = self.parse('''\
633 <xsl:stylesheet version="1.0"
634 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
635 xmlns:myns="testns"
636 exclude-result-prefixes="myns">
637 <xsl:template match="a"><A><xsl:value-of select="myns:mytext(b)"/></A></xsl:template>
638 </xsl:stylesheet>''')
639
640 def mytext(ctxt, values):
641 return 'X' * len(values)
642
643 namespace = etree.FunctionNamespace('testns')
644 namespace['mytext'] = mytext
645
646 result = tree.xslt(style)
647 self.assertEquals(self._rootstring(result),
648 _bytes('<A>X</A>'))
649
651 tree = self.parse('<a><b>B</b><b/></a>')
652 style = self.parse('''\
653 <xsl:stylesheet version="1.0"
654 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
655 xmlns:myns="testns"
656 exclude-result-prefixes="myns">
657 <xsl:template match="a">
658 <xsl:variable name="content">
659 <xsl:apply-templates/>
660 </xsl:variable>
661 <A><xsl:value-of select="myns:mytext($content)"/></A>
662 </xsl:template>
663 <xsl:template match="b"><xsl:copy>BBB</xsl:copy></xsl:template>
664 </xsl:stylesheet>''')
665
666 def mytext(ctxt, values):
667 for value in values:
668 self.assert_(hasattr(value, 'tag'),
669 "%s is not an Element" % type(value))
670 self.assertEquals(value.tag, 'b')
671 self.assertEquals(value.text, 'BBB')
672 return 'X'.join([el.tag for el in values])
673
674 namespace = etree.FunctionNamespace('testns')
675 namespace['mytext'] = mytext
676
677 result = tree.xslt(style)
678 self.assertEquals(self._rootstring(result),
679 _bytes('<A>bXb</A>'))
680
682 tree = self.parse('<a><b>B</b></a>')
683 style = self.parse('''\
684 <xsl:stylesheet version="1.0"
685 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
686 xmlns:myns="testns"
687 extension-element-prefixes="myns"
688 exclude-result-prefixes="myns">
689 <xsl:template match="a">
690 <A><myns:myext>b</myns:myext></A>
691 </xsl:template>
692 </xsl:stylesheet>''')
693
694 class MyExt(etree.XSLTExtension):
695 def execute(self, context, self_node, input_node, output_parent):
696 child = etree.Element(self_node.text)
697 child.text = 'X'
698 output_parent.append(child)
699
700 extensions = { ('testns', 'myext') : MyExt() }
701
702 result = tree.xslt(style, extensions=extensions)
703 self.assertEquals(self._rootstring(result),
704 _bytes('<A><b>X</b></A>'))
705
707 tree = self.parse('<a><b>B</b></a>')
708 style = self.parse('''\
709 <xsl:stylesheet version="1.0"
710 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
711 xmlns:myns="testns"
712 extension-element-prefixes="myns">
713 <xsl:template match="a">
714 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
715 </xsl:template>
716 </xsl:stylesheet>''')
717
718 class MyExt(etree.XSLTExtension):
719 def execute(self, context, self_node, input_node, output_parent):
720 output_parent.extend(list(self_node)[1:])
721
722 extensions = { ('testns', 'myext') : MyExt() }
723
724 result = tree.xslt(style, extensions=extensions)
725 self.assertEquals(self._rootstring(result),
726 _bytes('<A><y>Y</y><z/></A>'))
727
729 tree = self.parse('<a><b>B</b></a>')
730 style = self.parse('''\
731 <xsl:stylesheet version="1.0"
732 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
733 xmlns:myns="testns"
734 extension-element-prefixes="myns">
735 <xsl:template match="a">
736 <A><myns:myext><x>X</x><y>Y</y><z/></myns:myext></A>
737 </xsl:template>
738 <xsl:template match="x" />
739 <xsl:template match="z">XYZ</xsl:template>
740 </xsl:stylesheet>''')
741
742 class MyExt(etree.XSLTExtension):
743 def execute(self, context, self_node, input_node, output_parent):
744 for child in self_node:
745 for result in self.apply_templates(context, child):
746 if isinstance(result, basestring):
747 el = etree.Element("T")
748 el.text = result
749 else:
750 el = result
751 output_parent.append(el)
752
753 extensions = { ('testns', 'myext') : MyExt() }
754
755 result = tree.xslt(style, extensions=extensions)
756 self.assertEquals(self._rootstring(result),
757 _bytes('<A><T>Y</T><T>XYZ</T></A>'))
758
760 tree = self.parse('<a><b>B</b></a>')
761 style = self.parse('''\
762 <xsl:stylesheet version="1.0"
763 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
764 xmlns:myns="testns"
765 extension-element-prefixes="myns"
766 exclude-result-prefixes="myns">
767 <xsl:template match="a">
768 <A><myns:myext>b</myns:myext></A>
769 </xsl:template>
770 </xsl:stylesheet>''')
771
772 class MyError(Exception):
773 pass
774
775 class MyExt(etree.XSLTExtension):
776 def execute(self, context, self_node, input_node, output_parent):
777 raise MyError("expected!")
778
779 extensions = { ('testns', 'myext') : MyExt() }
780 self.assertRaises(MyError, tree.xslt, style, extensions=extensions)
781
783
784 xslt = etree.XSLT(etree.XML("""\
785 <xsl:stylesheet version="1.0"
786 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
787 <xsl:template match="/">
788 <test>TEXT<xsl:copy-of select="document('')//test"/></test>
789 </xsl:template>
790 </xsl:stylesheet>
791 """))
792 result = xslt(etree.XML('<a/>'))
793 root = result.getroot()
794 self.assertEquals(root.tag,
795 'test')
796 self.assertEquals(root[0].tag,
797 'test')
798 self.assertEquals(root[0].text,
799 'TEXT')
800 self.assertEquals(root[0][0].tag,
801 '{http://www.w3.org/1999/XSL/Transform}copy-of')
802
812
822
824 xslt = etree.XSLT(etree.XML("""\
825 <xsl:stylesheet version="1.0"
826 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
827 <xsl:template match="/">
828 <test>TEXT<xsl:copy-of select="document('uri:__junkfood__is__evil__')//test"/></test>
829 </xsl:template>
830 </xsl:stylesheet>
831 """))
832 self.assertRaises(etree.XSLTApplyError, xslt, etree.XML('<a/>'))
833
835
836 assertEquals = self.assertEquals
837 called = {'count' : 0}
838 class TestResolver(etree.Resolver):
839 def resolve(self, url, id, context):
840 assertEquals(url, 'file://ANYTHING')
841 called['count'] += 1
842 return self.resolve_string('<CALLED/>', context)
843
844 parser = etree.XMLParser()
845 parser.resolvers.add(TestResolver())
846
847 xslt = etree.XSLT(etree.XML(_bytes("""\
848 <xsl:stylesheet version="1.0"
849 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
850 xmlns:l="local">
851 <xsl:template match="/">
852 <test>
853 <xsl:for-each select="document('')//l:data/l:entry">
854 <xsl:copy-of select="document('file://ANYTHING')"/>
855 <xsl:copy>
856 <xsl:attribute name="value">
857 <xsl:value-of select="."/>
858 </xsl:attribute>
859 </xsl:copy>
860 </xsl:for-each>
861 </test>
862 </xsl:template>
863 <l:data>
864 <l:entry>A</l:entry>
865 <l:entry>B</l:entry>
866 </l:data>
867 </xsl:stylesheet>
868 """), parser))
869
870 self.assertEquals(called['count'], 0)
871 result = xslt(etree.XML('<a/>'))
872 self.assertEquals(called['count'], 1)
873
874 root = result.getroot()
875 self.assertEquals(root.tag,
876 'test')
877 self.assertEquals(len(root), 4)
878
879 self.assertEquals(root[0].tag,
880 'CALLED')
881 self.assertEquals(root[1].tag,
882 '{local}entry')
883 self.assertEquals(root[1].text,
884 None)
885 self.assertEquals(root[1].get("value"),
886 'A')
887 self.assertEquals(root[2].tag,
888 'CALLED')
889 self.assertEquals(root[3].tag,
890 '{local}entry')
891 self.assertEquals(root[3].text,
892 None)
893 self.assertEquals(root[3].get("value"),
894 'B')
895
897 assertEquals = self.assertEquals
898 called = {'count' : 0}
899 expected_url = None
900 class TestResolver(etree.Resolver):
901 def resolve(self, url, id, context):
902 assertEquals(url, expected_url)
903 called['count'] += 1
904 return self.resolve_string('<CALLED/>', context)
905
906 stylesheet_xml = _bytes("""\
907 <xsl:stylesheet version="1.0"
908 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
909 xmlns:l="local">
910 <xsl:template match="/">
911 <xsl:copy-of select="document('test.xml')"/>
912 </xsl:template>
913 </xsl:stylesheet>
914 """)
915
916 parser = etree.XMLParser()
917 parser.resolvers.add(TestResolver())
918
919
920 expected_url = 'test.xml'
921 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser))
922
923 self.assertEquals(called['count'], 0)
924 result = xslt(etree.XML('<a/>'))
925 self.assertEquals(called['count'], 1)
926
927
928 called['count'] = 0
929 expected_url = os.path.join('MY', 'BASE', 'test.xml')
930 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser,
931 base_url=os.path.join('MY', 'BASE', 'FILE')))
932
933 self.assertEquals(called['count'], 0)
934 result = xslt(etree.XML('<a/>'))
935 self.assertEquals(called['count'], 1)
936
937
938 called['count'] = 0
939 expected_url = 'http://server.com/BASE/DIR/test.xml'
940 xslt = etree.XSLT(etree.XML(stylesheet_xml, parser,
941 base_url='http://server.com/BASE/DIR/FILE'))
942
943 self.assertEquals(called['count'], 0)
944 result = xslt(etree.XML('<a/>'))
945 self.assertEquals(called['count'], 1)
946
957
963
969
971 root = etree.XML(_bytes('''\
972 <transform>
973 <widget displayType="fieldset"/>
974 </transform>'''))
975
976 xslt = etree.XSLT(etree.XML(_bytes('''\
977 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
978 <xsl:output method="html" indent="no"/>
979 <xsl:template match="/">
980 <html>
981 <xsl:apply-templates/>
982 </html>
983 </xsl:template>
984
985 <xsl:template match="widget">
986 <xsl:element name="{@displayType}"/>
987 </xsl:template>
988
989 </xsl:stylesheet>''')))
990
991 result = xslt(root[0])
992 root[:] = result.getroot()[:]
993 del root
994
996 tree = self.parse('''\
997 <?xml version="1.0"?>
998 <?xml-stylesheet type="text/xsl" href="%s"?>
999 <a>
1000 <b>B</b>
1001 <c>C</c>
1002 </a>''' % fileInTestDir("test1.xslt"))
1003
1004 style_root = tree.getroot().getprevious().parseXSL().getroot()
1005 self.assertEquals("{http://www.w3.org/1999/XSL/Transform}stylesheet",
1006 style_root.tag)
1007
1009
1010 tree = self.parse('''\
1011 <?xml version="1.0"?>
1012 <?xml-stylesheet type="text/xsl" href="#style"?>
1013 <a>
1014 <b>B</b>
1015 <c>C</c>
1016 <xsl:stylesheet version="1.0" xml:id="style"
1017 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1018 <xsl:template match="*" />
1019 <xsl:template match="/">
1020 <foo><xsl:value-of select="/a/b/text()" /></foo>
1021 </xsl:template>
1022 </xsl:stylesheet>
1023 </a>''')
1024
1025 style_root = tree.getroot().getprevious().parseXSL().getroot()
1026 self.assertEquals("{http://www.w3.org/1999/XSL/Transform}stylesheet",
1027 style_root.tag)
1028
1029 st = etree.XSLT(style_root)
1030 res = st(tree)
1031 self.assertEquals('''\
1032 <?xml version="1.0"?>
1033 <foo>B</foo>
1034 ''',
1035 str(res))
1036
1038
1039 tree = self.parse('''\
1040 <?xml version="1.0"?>
1041 <?xml-stylesheet type="text/xsl" href="#style"?>
1042 <a>
1043 <b>B</b>
1044 <c>C</c>
1045 </a>''')
1046
1047 style = self.parse('''\
1048 <xsl:stylesheet version="1.0" xml:id="style"
1049 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1050 <xsl:template match="*" />
1051 <xsl:template match="/">
1052 <foo><xsl:value-of select="/a/b/text()" /></foo>
1053 </xsl:template>
1054 </xsl:stylesheet>
1055 ''')
1056
1057 tree.getroot().append(style.getroot())
1058
1059 style_root = tree.getroot().getprevious().parseXSL().getroot()
1060 self.assertEquals("{http://www.w3.org/1999/XSL/Transform}stylesheet",
1061 style_root.tag)
1062
1063 st = etree.XSLT(style_root)
1064 res = st(tree)
1065 self.assertEquals('''\
1066 <?xml version="1.0"?>
1067 <foo>B</foo>
1068 ''',
1069 str(res))
1070
1072 tree = self.parse('''\
1073 <?xml version="1.0"?>
1074 <?xml-stylesheet type="text/xsl" href="TEST"?>
1075 <a>
1076 <b>B</b>
1077 <c>C</c>
1078 </a>''')
1079
1080 pi = tree.getroot().getprevious()
1081 self.assertEquals("TEST", pi.get("href"))
1082
1084 tree = self.parse('''\
1085 <?xml version="1.0"?>
1086 <?xml-stylesheet type="text/xsl" href="TEST"?>
1087 <a>
1088 <b>B</b>
1089 <c>C</c>
1090 </a>''')
1091
1092 pi = tree.getroot().getprevious()
1093 self.assertEquals("TEST", pi.get("href"))
1094 self.assertEquals("text/xsl", pi.get("type"))
1095 self.assertEquals(None, pi.get("motz"))
1096
1098 tree = self.parse('''\
1099 <?xml version="1.0"?>
1100 <?xml-stylesheet href="TEST" type="text/xsl"?>
1101 <a>
1102 <b>B</b>
1103 <c>C</c>
1104 </a>''')
1105
1106 pi = tree.getroot().getprevious()
1107 self.assertEquals("TEST", pi.get("href"))
1108 self.assertEquals("text/xsl", pi.get("type"))
1109 self.assertEquals(None, pi.get("motz"))
1110
1112 tree = self.parse('''\
1113 <?xml version="1.0"?>
1114 <?xml-stylesheet type="text/xsl" href="TEST"?>
1115 <a>
1116 <b>B</b>
1117 <c>C</c>
1118 </a>''')
1119
1120 pi = tree.getroot().getprevious()
1121 self.assertEquals(None, pi.get("unknownattribute"))
1122
1124 tree = self.parse('''\
1125 <?xml version="1.0"?>
1126 <?xml-stylesheet type="text/xsl" href="TEST"?>
1127 <a>
1128 <b>B</b>
1129 <c>C</c>
1130 </a>''')
1131
1132 pi = tree.getroot().getprevious()
1133 self.assertEquals("TEST", pi.get("href"))
1134
1135 pi.set("href", "TEST123")
1136 self.assertEquals("TEST123", pi.get("href"))
1137
1139 tree = self.parse('''\
1140 <?xml version="1.0"?>
1141 <?xml-stylesheet type="text/xsl"?>
1142 <a>
1143 <b>B</b>
1144 <c>C</c>
1145 </a>''')
1146
1147 pi = tree.getroot().getprevious()
1148 self.assertEquals(None, pi.get("href"))
1149
1150 pi.set("href", "TEST")
1151 self.assertEquals("TEST", pi.get("href"))
1152
1154 xslt = etree.XSLT(etree.XML(_bytes("""\
1155 <xsl:stylesheet version="1.0"
1156 xmlns:regexp="http://exslt.org/regular-expressions"
1157 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1158 <xsl:template match="*">
1159 <test><xsl:copy-of select="*[regexp:test(string(.), '8.')]"/></test>
1160 </xsl:template>
1161 </xsl:stylesheet>
1162 """)))
1163 result = xslt(etree.XML(_bytes('<a><b>123</b><b>098</b><b>987</b></a>')))
1164 root = result.getroot()
1165 self.assertEquals(root.tag,
1166 'test')
1167 self.assertEquals(len(root), 1)
1168 self.assertEquals(root[0].tag,
1169 'b')
1170 self.assertEquals(root[0].text,
1171 '987')
1172
1174 xslt = etree.XSLT(etree.XML("""\
1175 <xsl:stylesheet version="1.0"
1176 xmlns:regexp="http://exslt.org/regular-expressions"
1177 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1178 <xsl:template match="*">
1179 <test>
1180 <xsl:copy-of select="regexp:replace(string(.), 'd.', '', 'XX')"/>
1181 <xsl:text>-</xsl:text>
1182 <xsl:copy-of select="regexp:replace(string(.), 'd.', 'gi', 'XX')"/>
1183 </test>
1184 </xsl:template>
1185 </xsl:stylesheet>
1186 """))
1187 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1188 root = result.getroot()
1189 self.assertEquals(root.tag,
1190 'test')
1191 self.assertEquals(len(root), 0)
1192 self.assertEquals(root.text, 'abXXdEeDed-abXXXXeXXd')
1193
1195 xslt = etree.XSLT(etree.XML("""\
1196 <xsl:stylesheet version="1.0"
1197 xmlns:regexp="http://exslt.org/regular-expressions"
1198 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1199 <xsl:template match="*">
1200 <test>
1201 <test1><xsl:copy-of select="regexp:match(string(.), 'd.')"/></test1>
1202 <test2><xsl:copy-of select="regexp:match(string(.), 'd.', 'g')"/></test2>
1203 <test2i><xsl:copy-of select="regexp:match(string(.), 'd.', 'gi')"/></test2i>
1204 </test>
1205 </xsl:template>
1206 </xsl:stylesheet>
1207 """))
1208 result = xslt(etree.XML(_bytes('<a>abdCdEeDed</a>')))
1209 root = result.getroot()
1210 self.assertEquals(root.tag, 'test')
1211 self.assertEquals(len(root), 3)
1212
1213 self.assertEquals(len(root[0]), 1)
1214 self.assertEquals(root[0][0].tag, 'match')
1215 self.assertEquals(root[0][0].text, 'dC')
1216
1217 self.assertEquals(len(root[1]), 2)
1218 self.assertEquals(root[1][0].tag, 'match')
1219 self.assertEquals(root[1][0].text, 'dC')
1220 self.assertEquals(root[1][1].tag, 'match')
1221 self.assertEquals(root[1][1].text, 'dE')
1222
1223 self.assertEquals(len(root[2]), 3)
1224 self.assertEquals(root[2][0].tag, 'match')
1225 self.assertEquals(root[2][0].text, 'dC')
1226 self.assertEquals(root[2][1].tag, 'match')
1227 self.assertEquals(root[2][1].text, 'dE')
1228 self.assertEquals(root[2][2].tag, 'match')
1229 self.assertEquals(root[2][2].text, 'De')
1230
1232 xslt = etree.XSLT(etree.XML(_bytes("""\
1233 <xsl:stylesheet version="1.0"
1234 xmlns:regexp="http://exslt.org/regular-expressions"
1235 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1236 <xsl:template match="/">
1237 <test>
1238 <xsl:for-each select="regexp:match(
1239 '123abc567', '([0-9]+)([a-z]+)([0-9]+)' )">
1240 <test1><xsl:value-of select="."/></test1>
1241 </xsl:for-each>
1242 </test>
1243 </xsl:template>
1244 </xsl:stylesheet>
1245 """)))
1246 result = xslt(etree.XML(_bytes('<a/>')))
1247 root = result.getroot()
1248 self.assertEquals(root.tag, 'test')
1249 self.assertEquals(len(root), 4)
1250
1251 self.assertEquals(root[0].text, "123abc567")
1252 self.assertEquals(root[1].text, "123")
1253 self.assertEquals(root[2].text, "abc")
1254 self.assertEquals(root[3].text, "567")
1255
1257
1258 xslt = etree.XSLT(etree.XML(_bytes("""\
1259 <xsl:stylesheet version="1.0"
1260 xmlns:regexp="http://exslt.org/regular-expressions"
1261 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1262 <xsl:template match="/">
1263 <test>
1264 <xsl:for-each select="regexp:match(
1265 'http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml',
1266 '(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)')">
1267 <test1><xsl:value-of select="."/></test1>
1268 </xsl:for-each>
1269 </test>
1270 </xsl:template>
1271 </xsl:stylesheet>
1272 """)))
1273 result = xslt(etree.XML(_bytes('<a/>')))
1274 root = result.getroot()
1275 self.assertEquals(root.tag, 'test')
1276 self.assertEquals(len(root), 5)
1277
1278 self.assertEquals(
1279 root[0].text,
1280 "http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml")
1281 self.assertEquals(
1282 root[1].text,
1283 "http")
1284 self.assertEquals(
1285 root[2].text,
1286 "www.bayes.co.uk")
1287 self.assertFalse(root[3].text)
1288 self.assertEquals(
1289 root[4].text,
1290 "/xml/index.xml?/xml/utils/rechecker.xml")
1291
1293
1294 xslt = etree.XSLT(self.parse("""\
1295 <xsl:stylesheet version="1.0"
1296 xmlns:regexp="http://exslt.org/regular-expressions"
1297 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1298 <xsl:template match="/">
1299 <test>
1300 <xsl:for-each select="regexp:match(
1301 'This is a test string', '(\w+)', 'g')">
1302 <test1><xsl:value-of select="."/></test1>
1303 </xsl:for-each>
1304 </test>
1305 </xsl:template>
1306 </xsl:stylesheet>
1307 """))
1308 result = xslt(etree.XML(_bytes('<a/>')))
1309 root = result.getroot()
1310 self.assertEquals(root.tag, 'test')
1311 self.assertEquals(len(root), 5)
1312
1313 self.assertEquals(root[0].text, "This")
1314 self.assertEquals(root[1].text, "is")
1315 self.assertEquals(root[2].text, "a")
1316 self.assertEquals(root[3].text, "test")
1317 self.assertEquals(root[4].text, "string")
1318
1320
1321
1322 xslt = etree.XSLT(etree.XML(_bytes("""\
1323 <xsl:stylesheet version="1.0"
1324 xmlns:regexp="http://exslt.org/regular-expressions"
1325 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1326 <xsl:template match="/">
1327 <test>
1328 <xsl:for-each select="regexp:match(
1329 'This is a test string', '([a-z])+ ', 'g')">
1330 <test1><xsl:value-of select="."/></test1>
1331 </xsl:for-each>
1332 </test>
1333 </xsl:template>
1334 </xsl:stylesheet>
1335 """)))
1336 result = xslt(etree.XML(_bytes('<a/>')))
1337 root = result.getroot()
1338 self.assertEquals(root.tag, 'test')
1339 self.assertEquals(len(root), 4)
1340
1341 self.assertEquals(root[0].text, "his")
1342 self.assertEquals(root[1].text, "is")
1343 self.assertEquals(root[2].text, "a")
1344 self.assertEquals(root[3].text, "test")
1345
1347
1348
1349 xslt = etree.XSLT(etree.XML(_bytes("""\
1350 <xsl:stylesheet version="1.0"
1351 xmlns:regexp="http://exslt.org/regular-expressions"
1352 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1353 <xsl:template match="/">
1354 <test>
1355 <xsl:for-each select="regexp:match(
1356 'This is a test string', '([a-z])+ ', 'gi')">
1357 <test1><xsl:value-of select="."/></test1>
1358 </xsl:for-each>
1359 </test>
1360 </xsl:template>
1361 </xsl:stylesheet>
1362 """)))
1363 result = xslt(etree.XML(_bytes('<a/>')))
1364 root = result.getroot()
1365 self.assertEquals(root.tag, 'test')
1366 self.assertEquals(len(root), 4)
1367
1368 self.assertEquals(root[0].text, "This")
1369 self.assertEquals(root[1].text, "is")
1370 self.assertEquals(root[2].text, "a")
1371 self.assertEquals(root[3].text, "test")
1372
1373
1375 """XSLT tests for etree under Python 3"""
1377 tree = self.parse('<a><b>B</b><c>C</c></a>')
1378 style = self.parse('''\
1379 <xsl:stylesheet version="1.0"
1380 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1381 <xsl:template match="*" />
1382 <xsl:template match="/">
1383 <foo><xsl:value-of select="/a/b/text()" /></foo>
1384 </xsl:template>
1385 </xsl:stylesheet>''')
1386
1387 st = etree.XSLT(style)
1388 res = st(tree)
1389 self.assertEquals(_bytes('''\
1390 <?xml version="1.0"?>
1391 <foo>B</foo>
1392 '''),
1393 bytes(res))
1394
1396 tree = self.parse('<a><b>B</b><c>C</c></a>')
1397 style = self.parse('''\
1398 <xsl:stylesheet version="1.0"
1399 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1400 <xsl:template match="*" />
1401 <xsl:template match="/">
1402 <foo><xsl:value-of select="/a/b/text()" /></foo>
1403 </xsl:template>
1404 </xsl:stylesheet>''')
1405
1406 st = etree.XSLT(style)
1407 res = st(tree)
1408 self.assertEquals(_bytes('''\
1409 <?xml version="1.0"?>
1410 <foo>B</foo>
1411 '''),
1412 bytearray(res))
1413
1415 tree = self.parse('<a><b>B</b><c>C</c></a>')
1416 style = self.parse('''\
1417 <xsl:stylesheet version="1.0"
1418 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
1419 <xsl:template match="*" />
1420 <xsl:template match="/">
1421 <foo><xsl:value-of select="/a/b/text()" /></foo>
1422 </xsl:template>
1423 </xsl:stylesheet>''')
1424
1425 st = etree.XSLT(style)
1426 res = st(tree)
1427 self.assertEquals(_bytes('''\
1428 <?xml version="1.0"?>
1429 <foo>B</foo>
1430 '''),
1431 bytes(memoryview(res)))
1432
1433
1435 suite = unittest.TestSuite()
1436 suite.addTests([unittest.makeSuite(ETreeXSLTTestCase)])
1437 if is_python3:
1438 suite.addTests([unittest.makeSuite(Py3XSLTTestCase)])
1439 suite.addTests(
1440 [make_doctest('../../../doc/extensions.txt')])
1441 suite.addTests(
1442 [make_doctest('../../../doc/xpathxslt.txt')])
1443 return suite
1444
1445 if __name__ == '__main__':
1446 print('to test use test.py %s' % __file__)
1447