# -*- coding: utf-8 -*- """ Test cases related to XSLT processing """ from __future__ import absolute_import import io import sys import copy import gzip import os.path import unittest import contextlib from textwrap import dedent from tempfile import NamedTemporaryFile, mkdtemp is_python3 = sys.version_info[0] >= 3 try: unicode except NameError: # Python 3 unicode = str try: basestring except NameError: # Python 3 basestring = str from .common_imports import ( etree, BytesIO, HelperTestCase, fileInTestDir, _bytes, make_doctest, skipif, SimpleFSPath ) class ETreeXSLTTestCase(HelperTestCase): """XSLT tests etree""" def test_xslt(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) self.assertEqual('''\ B ''', str(res)) def test_xslt_elementtree_error(self): self.assertRaises(ValueError, etree.XSLT, etree.ElementTree()) def test_xslt_input_none(self): self.assertRaises(TypeError, etree.XSLT, None) def test_xslt_invalid_stylesheet(self): style = self.parse('''\ ''') self.assertRaises( etree.XSLTParseError, etree.XSLT, style) def test_xslt_copy(self): tree = self.parse('BC') style = self.parse('''\ ''') transform = etree.XSLT(style) res = transform(tree) self.assertEqual('''\ B ''', str(res)) transform_copy = copy.deepcopy(transform) res = transform_copy(tree) self.assertEqual('''\ B ''', str(res)) transform = etree.XSLT(style) res = transform(tree) self.assertEqual('''\ B ''', str(res)) @contextlib.contextmanager def _xslt_setup( self, encoding='UTF-16', expected_encoding=None, expected='\\uF8D2'): tree = self.parse(_bytes('\\uF8D2\\uF8D2' ).decode("unicode_escape")) style = self.parse('''\ ''' % {'ENCODING': encoding}) st = etree.XSLT(style) res = st(tree) expected = _bytes(dedent(expected).strip()).decode("unicode_escape").replace('\n', '') % { 'ENCODING': expected_encoding or encoding, } data = [res] yield data self.assertEqual(expected, data[0].replace('\n', '')) def test_xslt_utf8(self): with self._xslt_setup(encoding='UTF-8') as res: res[0] = unicode(bytes(res[0]), 'UTF-8') assert 'UTF-8' in res[0] def test_xslt_encoding(self): with self._xslt_setup() as res: res[0] = unicode(bytes(res[0]), 'UTF-16') assert 'UTF-16' in res[0] def test_xslt_encoding_override(self): with self._xslt_setup(encoding='UTF-8', expected_encoding='UTF-16') as res: f = BytesIO() res[0].write(f, encoding='UTF-16') if is_python3: output = str(f.getvalue(), 'UTF-16') else: output = unicode(str(f.getvalue()), 'UTF-16') res[0] = output.replace("'", '"') def test_xslt_write_output_bytesio(self): with self._xslt_setup() as res: f = BytesIO() res[0].write_output(f) res[0] = f.getvalue().decode('UTF-16') def test_xslt_write_output_failure(self): class Writer(object): def write(self, data): raise ValueError("FAILED!") try: with self._xslt_setup() as res: res[0].write_output(Writer()) except ValueError as exc: self.assertTrue("FAILED!" in str(exc), exc) else: self.assertTrue(False, "exception not raised") def test_xslt_write_output_file(self): with self._xslt_setup() as res: f = NamedTemporaryFile(delete=False) try: try: res[0].write_output(f) finally: f.close() with io.open(f.name, encoding='UTF-16') as f: res[0] = f.read() finally: os.unlink(f.name) def test_xslt_write_output_file_path(self): with self._xslt_setup() as res: f = NamedTemporaryFile(delete=False) try: try: res[0].write_output(f.name, compression=9) finally: f.close() with gzip.GzipFile(f.name) as f: res[0] = f.read().decode("UTF-16") finally: os.unlink(f.name) def test_xslt_write_output_file_pathlike(self): with self._xslt_setup() as res: f = NamedTemporaryFile(delete=False) try: try: res[0].write_output(SimpleFSPath(f.name), compression=9) finally: f.close() with gzip.GzipFile(f.name) as f: res[0] = f.read().decode("UTF-16") finally: os.unlink(f.name) def test_xslt_write_output_file_path_urlescaped(self): # libxml2 should not unescape file paths. with self._xslt_setup() as res: f = NamedTemporaryFile(prefix='tmp%2e', suffix='.xml.gz', delete=False) try: try: res[0].write_output(f.name, compression=3) finally: f.close() with gzip.GzipFile(f.name) as f: res[0] = f.read().decode("UTF-16") finally: os.unlink(f.name) def test_xslt_write_output_file_path_urlescaped_plus(self): with self._xslt_setup() as res: f = NamedTemporaryFile(prefix='p+%2e', suffix='.xml.gz', delete=False) try: try: res[0].write_output(f.name, compression=1) finally: f.close() with gzip.GzipFile(f.name) as f: res[0] = f.read().decode("UTF-16") finally: os.unlink(f.name) def test_xslt_write_output_file_oserror(self): with self._xslt_setup(expected='') as res: tempdir = mkdtemp() try: res[0].write_output(os.path.join(tempdir, 'missing_subdir', 'out.xml')) except IOError: res[0] = '' else: self.fail("IOError not raised") finally: os.rmdir(tempdir) def test_xslt_unicode(self): expected = ''' \\uF8D2 ''' with self._xslt_setup(expected=expected) as res: res[0] = unicode(res[0]) def test_xslt_unicode_standalone(self): tree = self.parse(_bytes('\\uF8D2\\uF8D2' ).decode("unicode_escape")) style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) expected = _bytes('''\ \\uF8D2 ''').decode("unicode_escape") self.assertEqual(expected, unicode(res)) def test_xslt_input(self): style = self.parse('''\ ''') st = etree.XSLT(style) st = etree.XSLT(style.getroot()) def test_xslt_input_partial_doc(self): style = self.parse('''\ ''') self.assertRaises(etree.XSLTParseError, etree.XSLT, style) root_node = style.getroot() self.assertRaises(etree.XSLTParseError, etree.XSLT, root_node) st = etree.XSLT(root_node[0]) def test_xslt_broken(self): style = self.parse('''\ ''') self.assertRaises(etree.XSLTParseError, etree.XSLT, style) def test_xslt_parsing_error_log(self): tree = self.parse('') style = self.parse('''\ ''') self.assertRaises(etree.XSLTParseError, etree.XSLT, style) exc = None try: etree.XSLT(style) except etree.XSLTParseError as e: exc = e else: self.assertFalse(True, "XSLT processing should have failed but didn't") self.assertTrue(exc is not None) self.assertTrue(len(exc.error_log)) for error in exc.error_log: self.assertTrue(':ERROR:XSLT:' in str(error)) def test_xslt_apply_error_log(self): tree = self.parse('') style = self.parse('''\ FAIL ''') self.assertRaises(etree.XSLTApplyError, etree.XSLT(style), tree) transform = etree.XSLT(style) exc = None try: transform(tree) except etree.XSLTApplyError as e: exc = e else: self.assertFalse(True, "XSLT processing should have failed but didn't") self.assertTrue(exc is not None) self.assertTrue(len(exc.error_log)) self.assertEqual(len(transform.error_log), len(exc.error_log)) for error in exc.error_log: self.assertTrue(':ERROR:XSLT:' in str(error)) for error in transform.error_log: self.assertTrue(':ERROR:XSLT:' in str(error)) def test_xslt_parameters(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree, bar="'Bar'") self.assertEqual('''\ Bar ''', str(res)) def test_xslt_string_parameters(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree, bar=etree.XSLT.strparam('''it's me, "Bar"''')) self.assertEqual('''\ it's me, "Bar" ''', str(res)) def test_xslt_parameter_invalid(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = self.assertRaises(etree.XSLTApplyError, st, tree, bar="") res = self.assertRaises(etree.XSLTApplyError, st, tree, bar="....") def test_xslt_parameter_missing(self): # apply() without needed parameter will lead to XSLTApplyError tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) # at least libxslt 1.1.28 produces this error, earlier ones (e.g. 1.1.18) might not ... self.assertRaises(etree.XSLTApplyError, st.apply, tree) def test_xslt_multiple_parameters(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree, bar="'Bar'", baz="'Baz'") self.assertEqual('''\ BarBaz ''', str(res)) def test_xslt_parameter_xpath(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree, bar="/a/b/text()") self.assertEqual('''\ B ''', str(res)) def test_xslt_parameter_xpath_object(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree, bar=etree.XPath("/a/b/text()")) self.assertEqual('''\ B ''', str(res)) def test_xslt_default_parameters(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree, bar="'Bar'") self.assertEqual('''\ Bar ''', str(res)) res = st(tree) self.assertEqual('''\ Default ''', str(res)) def test_xslt_html_output(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) self.assertEqual('B', str(res).strip()) def test_xslt_include(self): tree = etree.parse(fileInTestDir('test1.xslt')) st = etree.XSLT(tree) def test_xslt_include_from_filelike(self): f = open(fileInTestDir('test1.xslt'), 'rb') tree = etree.parse(f) f.close() st = etree.XSLT(tree) def test_xslt_multiple_transforms(self): xml = '' xslt = '''\ Some text ''' source = self.parse(xml) styledoc = self.parse(xslt) style = etree.XSLT(styledoc) result = style(source) etree.tostring(result.getroot()) source = self.parse(xml) styledoc = self.parse(xslt) style = etree.XSLT(styledoc) result = style(source) etree.tostring(result.getroot()) def test_xslt_repeat_transform(self): xml = '' xslt = '''\ Some text ''' source = self.parse(xml) styledoc = self.parse(xslt) transform = etree.XSLT(styledoc) result = transform(source) result = transform(source) etree.tostring(result.getroot()) result = transform(source) etree.tostring(result.getroot()) str(result) result1 = transform(source) result2 = transform(source) self.assertEqual(str(result1), str(result2)) result = transform(source) str(result) def test_xslt_empty(self): # could segfault if result contains "empty document" xml = '' xslt = ''' ''' source = self.parse(xml) styledoc = self.parse(xslt) style = etree.XSLT(styledoc) result = style(source) self.assertEqual('', str(result)) def test_xslt_message(self): xml = '' xslt = ''' TEST TEST TEST ''' source = self.parse(xml) styledoc = self.parse(xslt) style = etree.XSLT(styledoc) result = style(source) self.assertEqual('', str(result)) self.assertTrue("TEST TEST TEST" in [entry.message for entry in style.error_log]) def test_xslt_message_terminate(self): xml = '' xslt = ''' TEST TEST TEST ''' source = self.parse(xml) styledoc = self.parse(xslt) style = etree.XSLT(styledoc) self.assertRaises(etree.XSLTApplyError, style, source) self.assertTrue("TEST TEST TEST" in [entry.message for entry in style.error_log]) def test_xslt_shortcut(self): tree = self.parse('BC') style = self.parse('''\ ''') result = tree.xslt(style, bar="'Bar'", baz="'Baz'") self.assertEqual( _bytes('BarBaz'), etree.tostring(result.getroot())) def test_multiple_elementrees(self): tree = self.parse('BC') style = self.parse('''\ ''') self.assertEqual(self._rootstring(tree), _bytes('BC')) result = tree.xslt(style) self.assertEqual(self._rootstring(tree), _bytes('BC')) self.assertEqual(self._rootstring(result), _bytes('BC')) b_tree = etree.ElementTree(tree.getroot()[0]) self.assertEqual(self._rootstring(b_tree), _bytes('B')) result = b_tree.xslt(style) self.assertEqual(self._rootstring(tree), _bytes('BC')) self.assertEqual(self._rootstring(result), _bytes('B')) c_tree = etree.ElementTree(tree.getroot()[1]) self.assertEqual(self._rootstring(c_tree), _bytes('C')) result = c_tree.xslt(style) self.assertEqual(self._rootstring(tree), _bytes('BC')) self.assertEqual(self._rootstring(result), _bytes('C')) def test_xslt_document_XML(self): # make sure document('') works from parsed strings xslt = etree.XSLT(etree.XML("""\ TEXT """)) result = xslt(etree.XML('')) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(root[0].tag, 'test') self.assertEqual(root[0].text, 'TEXT') self.assertEqual(root[0][0].tag, '{http://www.w3.org/1999/XSL/Transform}copy-of') def test_xslt_document_parse(self): # make sure document('') works from loaded files xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt"))) result = xslt(etree.XML('')) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(root[0].tag, '{http://www.w3.org/1999/XSL/Transform}stylesheet') def test_xslt_document_elementtree(self): # make sure document('') works from loaded files xslt = etree.XSLT(etree.ElementTree(file=fileInTestDir("test-document.xslt"))) result = xslt(etree.XML('')) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(root[0].tag, '{http://www.w3.org/1999/XSL/Transform}stylesheet') def test_xslt_document_error(self): xslt = etree.XSLT(etree.XML("""\ TEXT """)) errors = None try: xslt(etree.XML('')) except etree.XSLTApplyError as exc: errors = exc.error_log else: self.assertFalse(True, "XSLT processing should have failed but didn't") self.assertTrue(len(errors)) for error in errors: if ':ERROR:XSLT:' in str(error): break else: self.assertFalse(True, 'No XSLT errors found in error log:\n%s' % errors) def test_xslt_document_XML_resolver(self): # make sure document('') works when custom resolvers are in use assertEqual = self.assertEqual called = {'count' : 0} class TestResolver(etree.Resolver): def resolve(self, url, id, context): assertEqual(url, 'file://ANYTHING') called['count'] += 1 return self.resolve_string('', context) parser = etree.XMLParser() parser.resolvers.add(TestResolver()) xslt = etree.XSLT(etree.XML(_bytes("""\ A B """), parser)) self.assertEqual(called['count'], 0) result = xslt(etree.XML('')) self.assertEqual(called['count'], 1) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 4) self.assertEqual(root[0].tag, 'CALLED') self.assertEqual(root[1].tag, '{local}entry') self.assertEqual(root[1].text, None) self.assertEqual(root[1].get("value"), 'A') self.assertEqual(root[2].tag, 'CALLED') self.assertEqual(root[3].tag, '{local}entry') self.assertEqual(root[3].text, None) self.assertEqual(root[3].get("value"), 'B') def test_xslt_resolver_url_building(self): assertEqual = self.assertEqual called = {'count' : 0} expected_url = None class TestResolver(etree.Resolver): def resolve(self, url, id, context): assertEqual(url, expected_url) called['count'] += 1 return self.resolve_string('', context) stylesheet_xml = _bytes("""\ """) parser = etree.XMLParser() parser.resolvers.add(TestResolver()) # test without base_url => relative path only expected_url = 'test.xml' xslt = etree.XSLT(etree.XML(stylesheet_xml, parser)) self.assertEqual(called['count'], 0) result = xslt(etree.XML('')) self.assertEqual(called['count'], 1) # now the same thing with a stylesheet base URL on the filesystem called['count'] = 0 expected_url = 'MY/BASE/test.xml' # seems to be the same on Windows xslt = etree.XSLT(etree.XML( stylesheet_xml, parser, base_url=os.path.join('MY', 'BASE', 'FILE'))) self.assertEqual(called['count'], 0) result = xslt(etree.XML('')) self.assertEqual(called['count'], 1) # now the same thing with a stylesheet base URL called['count'] = 0 expected_url = 'http://server.com/BASE/DIR/test.xml' xslt = etree.XSLT(etree.XML( stylesheet_xml, parser, base_url='http://server.com/BASE/DIR/FILE')) self.assertEqual(called['count'], 0) result = xslt(etree.XML('')) self.assertEqual(called['count'], 1) # now the same thing with a stylesheet base file:// URL called['count'] = 0 expected_url = 'file://BASE/DIR/test.xml' xslt = etree.XSLT(etree.XML( stylesheet_xml, parser, base_url='file://BASE/DIR/FILE')) self.assertEqual(called['count'], 0) result = xslt(etree.XML('')) self.assertEqual(called['count'], 1) def test_xslt_document_parse_allow(self): access_control = etree.XSLTAccessControl(read_file=True) xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt")), access_control=access_control) result = xslt(etree.XML('')) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(root[0].tag, '{http://www.w3.org/1999/XSL/Transform}stylesheet') def test_xslt_document_parse_deny(self): access_control = etree.XSLTAccessControl(read_file=False) xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt")), access_control=access_control) self.assertRaises(etree.XSLTApplyError, xslt, etree.XML('')) def test_xslt_document_parse_deny_all(self): access_control = etree.XSLTAccessControl.DENY_ALL xslt = etree.XSLT(etree.parse(fileInTestDir("test-document.xslt")), access_control=access_control) self.assertRaises(etree.XSLTApplyError, xslt, etree.XML('')) def test_xslt_access_control_repr(self): access_control = etree.XSLTAccessControl.DENY_ALL self.assertTrue(repr(access_control).startswith(type(access_control).__name__)) self.assertEqual(repr(access_control), repr(access_control)) self.assertNotEqual(repr(etree.XSLTAccessControl.DENY_ALL), repr(etree.XSLTAccessControl.DENY_WRITE)) self.assertNotEqual(repr(etree.XSLTAccessControl.DENY_ALL), repr(etree.XSLTAccessControl())) def test_xslt_move_result(self): root = etree.XML(_bytes('''\ ''')) xslt = etree.XSLT(etree.XML(_bytes('''\ '''))) result = xslt(root[0]) root[:] = result.getroot()[:] del root # segfaulted before def test_xslt_pi(self): tree = self.parse('''\ B C ''' % fileInTestDir("test1.xslt")) style_root = tree.getroot().getprevious().parseXSL().getroot() self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet", style_root.tag) def test_xslt_pi_embedded_xmlid(self): # test xml:id dictionary lookup mechanism tree = self.parse('''\ B C ''') style_root = tree.getroot().getprevious().parseXSL().getroot() self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet", style_root.tag) st = etree.XSLT(style_root) res = st(tree) self.assertEqual('''\ B ''', str(res)) def test_xslt_pi_embedded_id(self): # test XPath lookup mechanism tree = self.parse('''\ B C ''') style = self.parse('''\ ''') tree.getroot().append(style.getroot()) style_root = tree.getroot().getprevious().parseXSL().getroot() self.assertEqual("{http://www.w3.org/1999/XSL/Transform}stylesheet", style_root.tag) st = etree.XSLT(style_root) res = st(tree) self.assertEqual('''\ B ''', str(res)) def test_xslt_pi_get(self): tree = self.parse('''\ B C ''') pi = tree.getroot().getprevious() self.assertEqual("TEST", pi.get("href")) def test_xslt_pi_get_all(self): tree = self.parse('''\ B C ''') pi = tree.getroot().getprevious() self.assertEqual("TEST", pi.get("href")) self.assertEqual("text/xsl", pi.get("type")) self.assertEqual(None, pi.get("motz")) def test_xslt_pi_get_all_reversed(self): tree = self.parse('''\ B C ''') pi = tree.getroot().getprevious() self.assertEqual("TEST", pi.get("href")) self.assertEqual("text/xsl", pi.get("type")) self.assertEqual(None, pi.get("motz")) def test_xslt_pi_get_unknown(self): tree = self.parse('''\ B C ''') pi = tree.getroot().getprevious() self.assertEqual(None, pi.get("unknownattribute")) def test_xslt_pi_set_replace(self): tree = self.parse('''\ B C ''') pi = tree.getroot().getprevious() self.assertEqual("TEST", pi.get("href")) pi.set("href", "TEST123") self.assertEqual("TEST123", pi.get("href")) def test_xslt_pi_set_new(self): tree = self.parse('''\ B C ''') pi = tree.getroot().getprevious() self.assertEqual(None, pi.get("href")) pi.set("href", "TEST") self.assertEqual("TEST", pi.get("href")) class ETreeEXSLTTestCase(HelperTestCase): """EXSLT tests""" def test_exslt_str(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) self.assertEqual('''\ *B**C* ''', str(res)) def test_exslt_str_attribute_replace(self): tree = self.parse('BC') style = self.parse('''\

test

''') st = etree.XSLT(style) res = st(tree) self.assertEqual(str(res), '''\

test

''') def test_exslt_math(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) self.assertEqual('''\ BC ''', str(res)) def test_exslt_regexp_test(self): xslt = etree.XSLT(etree.XML(_bytes("""\ """))) result = xslt(etree.XML(_bytes('123098987'))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 1) self.assertEqual(root[0].tag, 'b') self.assertEqual(root[0].text, '987') def test_exslt_regexp_replace(self): xslt = etree.XSLT(etree.XML("""\ - """)) result = xslt(etree.XML(_bytes('abdCdEeDed'))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 0) self.assertEqual(root.text, 'abXXdEeDed-abXXXXeXXd') def test_exslt_regexp_match(self): xslt = etree.XSLT(etree.XML("""\ """)) result = xslt(etree.XML(_bytes('abdCdEeDed'))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 3) self.assertEqual(len(root[0]), 1) self.assertEqual(root[0][0].tag, 'match') self.assertEqual(root[0][0].text, 'dC') self.assertEqual(len(root[1]), 2) self.assertEqual(root[1][0].tag, 'match') self.assertEqual(root[1][0].text, 'dC') self.assertEqual(root[1][1].tag, 'match') self.assertEqual(root[1][1].text, 'dE') self.assertEqual(len(root[2]), 3) self.assertEqual(root[2][0].tag, 'match') self.assertEqual(root[2][0].text, 'dC') self.assertEqual(root[2][1].tag, 'match') self.assertEqual(root[2][1].text, 'dE') self.assertEqual(root[2][2].tag, 'match') self.assertEqual(root[2][2].text, 'De') def test_exslt_regexp_match_groups(self): xslt = etree.XSLT(etree.XML(_bytes("""\ """))) result = xslt(etree.XML(_bytes(''))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 4) self.assertEqual(root[0].text, "123abc567") self.assertEqual(root[1].text, "123") self.assertEqual(root[2].text, "abc") self.assertEqual(root[3].text, "567") def test_exslt_regexp_match1(self): # taken from http://www.exslt.org/regexp/functions/match/index.html xslt = etree.XSLT(etree.XML(_bytes("""\ """))) result = xslt(etree.XML(_bytes(''))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 5) self.assertEqual( root[0].text, "http://www.bayes.co.uk/xml/index.xml?/xml/utils/rechecker.xml") self.assertEqual( root[1].text, "http") self.assertEqual( root[2].text, "www.bayes.co.uk") self.assertFalse(root[3].text) self.assertEqual( root[4].text, "/xml/index.xml?/xml/utils/rechecker.xml") def test_exslt_regexp_match2(self): # taken from http://www.exslt.org/regexp/functions/match/index.html xslt = etree.XSLT(self.parse("""\ """)) result = xslt(etree.XML(_bytes(''))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 5) self.assertEqual(root[0].text, "This") self.assertEqual(root[1].text, "is") self.assertEqual(root[2].text, "a") self.assertEqual(root[3].text, "test") self.assertEqual(root[4].text, "string") def _test_exslt_regexp_match3(self): # taken from http://www.exslt.org/regexp/functions/match/index.html # THIS IS NOT SUPPORTED! xslt = etree.XSLT(etree.XML(_bytes("""\ """))) result = xslt(etree.XML(_bytes(''))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 4) self.assertEqual(root[0].text, "his") self.assertEqual(root[1].text, "is") self.assertEqual(root[2].text, "a") self.assertEqual(root[3].text, "test") def _test_exslt_regexp_match4(self): # taken from http://www.exslt.org/regexp/functions/match/index.html # THIS IS NOT SUPPORTED! xslt = etree.XSLT(etree.XML(_bytes("""\ """))) result = xslt(etree.XML(_bytes(''))) root = result.getroot() self.assertEqual(root.tag, 'test') self.assertEqual(len(root), 4) self.assertEqual(root[0].text, "This") self.assertEqual(root[1].text, "is") self.assertEqual(root[2].text, "a") self.assertEqual(root[3].text, "test") class ETreeXSLTExtFuncTestCase(HelperTestCase): """Tests for XPath extension functions in XSLT.""" def test_extensions1(self): tree = self.parse('B') style = self.parse('''\ ''') def mytext(ctxt, values): return 'X' * len(values) result = tree.xslt(style, {('testns', 'mytext') : mytext}) self.assertEqual(self._rootstring(result), _bytes('X')) def test_extensions2(self): tree = self.parse('B') style = self.parse('''\ ''') def mytext(ctxt, values): return 'X' * len(values) namespace = etree.FunctionNamespace('testns') namespace['mytext'] = mytext result = tree.xslt(style) self.assertEqual(self._rootstring(result), _bytes('X')) def test_variable_result_tree_fragment(self): tree = self.parse('B') style = self.parse('''\ BBB ''') def mytext(ctxt, values): for value in values: self.assertTrue(hasattr(value, 'tag'), "%s is not an Element" % type(value)) self.assertEqual(value.tag, 'b') self.assertEqual(value.text, 'BBB') return 'X'.join([el.tag for el in values]) namespace = etree.FunctionNamespace('testns') namespace['mytext'] = mytext result = tree.xslt(style) self.assertEqual(self._rootstring(result), _bytes('bXb')) def test_xpath_on_context_node(self): tree = self.parse('BC') style = self.parse('''\ ''') def extfunc(ctxt): text_content = ctxt.context_node.xpath('text()') return 'x'.join(text_content) namespace = etree.FunctionNamespace('testns') namespace['myext'] = extfunc result = tree.xslt(style) self.assertEqual(self._rootstring(result), _bytes('BxC')) def test_xpath_on_foreign_context_node(self): # LP ticket 1354652 class Resolver(etree.Resolver): def resolve(self, system_url, public_id, context): assert system_url == 'extdoc.xml' return self.resolve_string(b'BC', context) parser = etree.XMLParser() parser.resolvers.add(Resolver()) tree = self.parse(b'') transform = etree.XSLT(self.parse(b'''\ ''', parser=parser)) def extfunc(ctxt): text_content = ctxt.context_node.xpath('text()') return 'x'.join(text_content) namespace = etree.FunctionNamespace('testns') namespace['myext'] = extfunc result = transform(tree) self.assertEqual(self._rootstring(result), _bytes('BxC')) class ETreeXSLTExtElementTestCase(HelperTestCase): """Tests for extension elements in XSLT.""" def test_extension_element(self): tree = self.parse('B') style = self.parse('''\ b ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): child = etree.Element(self_node.text) child.text = 'X' output_parent.append(child) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('X')) def test_extension_element_doc_context(self): tree = self.parse('B') style = self.parse('''\ b ''') tags = [] class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): tags.append(input_node.tag) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(tags, ['a']) def test_extension_element_comment_pi_context(self): tree = self.parse('') style = self.parse('''\ b b ''') text = [] class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): text.append(input_node.text) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(text, ['toast', 'a comment', 'pi']) def _test_extension_element_attribute_context(self): # currently not supported tree = self.parse('') style = self.parse('''\ b b ''') text = [] class MyExt(etree.XSLTExtension): def execute(self, context, self_node, attr_value, output_parent): text.append(attr_value) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(text, ['A', 'B']) def test_extension_element_content(self): tree = self.parse('B') style = self.parse('''\ XY ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): output_parent.extend(list(self_node)[1:]) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('Y')) def test_extension_element_apply_templates(self): tree = self.parse('B') style = self.parse('''\ XY XYZ ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): for child in self_node: for result in self.apply_templates(context, child): if isinstance(result, basestring): el = etree.Element("T") el.text = result else: el = result output_parent.append(el) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('YXYZ')) def test_extension_element_apply_templates_elements_only(self): tree = self.parse('B') style = self.parse('''\ XY XYZ ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): for child in self_node: for result in self.apply_templates(context, child, elements_only=True): assert not isinstance(result, basestring) output_parent.append(result) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('')) def test_extension_element_apply_templates_remove_blank_text(self): tree = self.parse('B') style = self.parse('''\ XY XYZ ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): for child in self_node: for result in self.apply_templates(context, child, remove_blank_text=True): if isinstance(result, basestring): assert result.strip() el = etree.Element("T") el.text = result else: el = result output_parent.append(el) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('XYZ')) def test_extension_element_apply_templates_target_node(self): tree = self.parse('B') style = self.parse('''\ XY XYZ ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): for child in self_node: self.apply_templates(context, child, output_parent) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('YXYZ')) def test_extension_element_apply_templates_target_node_doc(self): tree = self.parse('B') style = self.parse('''\ XY TEST XYZ TEST ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): for child in self_node: self.apply_templates(context, child, output_parent) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(etree.tostring(result), _bytes('XYZ')) def test_extension_element_process_children(self): tree = self.parse('E') style = self.parse('''\ yo ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): el = etree.Element('MY') self.process_children(context, el) output_parent.append(el) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('E')) def test_extension_element_process_children_to_append_only(self): tree = self.parse('') style = self.parse('''\
''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): self.process_children(context, output_parent) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('')) def test_extension_element_process_children_to_read_only_raise(self): tree = self.parse('') style = self.parse('''\ ''') class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): self.process_children(context, self_node) extensions = { ('testns', 'myext') : MyExt() } self.assertRaises(TypeError, tree.xslt, style, extensions=extensions) def test_extension_element_process_children_with_subextension_element(self): tree = self.parse('') style = self.parse('''\ ''') class MyExt(etree.XSLTExtension): callback_call_counter = 0 def execute(self, context, self_node, input_node, output_parent): self.callback_call_counter += 1 el = etree.Element('MY', n=str(self.callback_call_counter)) self.process_children(context, el) output_parent.append(el) extensions = { ('testns', 'myext') : MyExt() } result = tree.xslt(style, extensions=extensions) self.assertEqual(self._rootstring(result), _bytes('')) def test_extension_element_raise(self): tree = self.parse('B') style = self.parse('''\ b ''') class MyError(Exception): pass class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): raise MyError("expected!") extensions = { ('testns', 'myext') : MyExt() } self.assertRaises(MyError, tree.xslt, style, extensions=extensions) # FIXME: DISABLED - implementation seems to be broken # if someone cares enough about this feature, I take pull requests that fix it. def _test_multiple_extension_elements_with_output_parent(self): tree = self.parse("""\ This is arbitrary text in a paragraph """) style = self.parse("""\ """) test = self calls = [] class ExtMyPar(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): calls.append('par') p = etree.Element("p") p.attrib["style"] = "color:red" self.process_children(context, p) output_parent.append(p) class ExtMyFormat(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): calls.append('format') content = self.process_children(context) test.assertEqual(1, len(content)) test.assertEqual('arbitrary', content[0]) test.assertEqual('This is ', output_parent.text) output_parent.text += '*-%s-*' % content[0] extensions = {("my", "par"): ExtMyPar(), ("my", "format"): ExtMyFormat()} transform = etree.XSLT(style, extensions=extensions) result = transform(tree) self.assertEqual(['par', 'format'], calls) self.assertEqual( b'

This is *-arbitrary-* text in a paragraph

\n', etree.tostring(result)) def test_extensions_nsmap(self): tree = self.parse("""\ test """) style = self.parse("""\ """) class MyExt(etree.XSLTExtension): def execute(self, context, self_node, input_node, output_parent): output_parent.text = str(input_node.nsmap) extensions = {('extns', 'show-nsmap'): MyExt()} result = tree.xslt(style, extensions=extensions) self.assertEqual(etree.tostring(result, pretty_print=True), b"""\ {'sha256': 'http://www.w3.org/2001/04/xmlenc#sha256'} """) class Py3XSLTTestCase(HelperTestCase): """XSLT tests for etree under Python 3""" pytestmark = skipif('sys.version_info < (3,0)') def test_xslt_result_bytes(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) self.assertEqual(_bytes('''\ B '''), bytes(res)) def test_xslt_result_bytearray(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) self.assertEqual(_bytes('''\ B '''), bytearray(res)) def test_xslt_result_memoryview(self): tree = self.parse('BC') style = self.parse('''\ ''') st = etree.XSLT(style) res = st(tree) self.assertEqual(_bytes('''\ B '''), bytes(memoryview(res))) def test_suite(): suite = unittest.TestSuite() suite.addTests([unittest.makeSuite(ETreeXSLTTestCase)]) suite.addTests([unittest.makeSuite(ETreeEXSLTTestCase)]) suite.addTests([unittest.makeSuite(ETreeXSLTExtFuncTestCase)]) suite.addTests([unittest.makeSuite(ETreeXSLTExtElementTestCase)]) if is_python3: suite.addTests([unittest.makeSuite(Py3XSLTTestCase)]) suite.addTests( [make_doctest('../../../doc/extensions.txt')]) suite.addTests( [make_doctest('../../../doc/xpathxslt.txt')]) return suite if __name__ == '__main__': print('to test use test.py %s' % __file__)