Mercurial > genshi > mirror
annotate genshi/tests/path.py @ 1043:a21009a2bc3a trunk
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
author | hodgestar |
---|---|
date | Thu, 20 Mar 2014 12:58:48 +0000 |
parents | f91289c7d092 |
children |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
66
59eb24184e9c
Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents:
38
diff
changeset
|
3 # Copyright (C) 2006 Edgewall Software |
1 | 4 # All rights reserved. |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
230 | 8 # are also available at http://genshi.edgewall.org/wiki/License. |
1 | 9 # |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
230 | 12 # history and logs, available at http://genshi.edgewall.org/log/. |
1 | 13 |
14 import doctest | |
15 import unittest | |
16 | |
1043
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
17 from genshi.core import Attrs, QName |
230 | 18 from genshi.input import XML |
818 | 19 from genshi.path import Path, PathParser, PathSyntaxError, GenericStrategy, \ |
20 SingleStepStrategy, SimplePathStrategy | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
21 |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
22 |
818 | 23 class FakePath(Path): |
24 def __init__(self, strategy): | |
25 self.strategy = strategy | |
26 def test(self, ignore_context = False): | |
27 return self.strategy.test(ignore_context) | |
28 | |
832 | 29 |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
30 class PathTestCase(unittest.TestCase): |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
31 |
818 | 32 strategies = [GenericStrategy, SingleStepStrategy, SimplePathStrategy] |
33 | |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
34 def test_error_no_absolute_path(self): |
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
35 self.assertRaises(PathSyntaxError, Path, '/root') |
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
36 |
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
37 def test_error_unsupported_axis(self): |
137 | 38 self.assertRaises(PathSyntaxError, Path, '..') |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
39 self.assertRaises(PathSyntaxError, Path, 'parent::ma') |
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
40 |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
41 def test_1step(self): |
38
ee669cb9cccc
Fix for #2 (incorrect context node in path expressions). Still some paths that produce incorrect results, but the common case seems to work now.
cmlenz
parents:
27
diff
changeset
|
42 xml = XML('<root><elem/></root>') |
832 | 43 self._test_eval( |
44 path = 'elem', | |
45 equiv = '<Path "child::elem">', | |
46 input = xml, | |
47 output = '<elem/>' | |
48 ) | |
49 self._test_eval( | |
50 path = 'elem', | |
51 equiv = '<Path "child::elem">', | |
52 input = xml, | |
53 output = '<elem/>' | |
54 ) | |
55 self._test_eval( | |
56 path = 'child::elem', | |
57 equiv = '<Path "child::elem">', | |
58 input = xml, | |
59 output = '<elem/>' | |
60 ) | |
61 self._test_eval( | |
62 path = '//elem', | |
63 equiv = '<Path "descendant-or-self::elem">', | |
64 input = xml, | |
65 output = '<elem/>' | |
66 ) | |
67 self._test_eval( | |
68 path = 'descendant::elem', | |
69 equiv = '<Path "descendant::elem">', | |
70 input = xml, | |
71 output = '<elem/>' | |
72 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
73 |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
74 def test_1step_self(self): |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
75 xml = XML('<root><elem/></root>') |
832 | 76 self._test_eval( |
77 path = '.', | |
78 equiv = '<Path "self::node()">', | |
79 input = xml, | |
80 output = '<root><elem/></root>' | |
81 ) | |
82 self._test_eval( | |
83 path = 'self::node()', | |
84 equiv = '<Path "self::node()">', | |
85 input = xml, | |
86 output = '<root><elem/></root>' | |
87 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
88 |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
89 def test_1step_wildcard(self): |
38
ee669cb9cccc
Fix for #2 (incorrect context node in path expressions). Still some paths that produce incorrect results, but the common case seems to work now.
cmlenz
parents:
27
diff
changeset
|
90 xml = XML('<root><elem/></root>') |
832 | 91 self._test_eval( |
92 path = '*', | |
93 equiv = '<Path "child::*">', | |
94 input = xml, | |
95 output = '<elem/>' | |
96 ) | |
97 self._test_eval( | |
98 path = 'child::*', | |
99 equiv = '<Path "child::*">', | |
100 input = xml, | |
101 output = '<elem/>' | |
102 ) | |
103 self._test_eval( | |
104 path = 'child::node()', | |
105 equiv = '<Path "child::node()">', | |
106 input = xml, | |
107 output = '<elem/>' | |
108 ) | |
109 self._test_eval( | |
110 path = '//*', | |
111 equiv = '<Path "descendant-or-self::*">', | |
112 input = xml, | |
113 output = '<root><elem/></root>' | |
114 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
115 |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
116 def test_1step_attribute(self): |
832 | 117 self._test_eval( |
118 path = '@foo', | |
119 equiv = '<Path "attribute::foo">', | |
120 input = XML('<root/>'), | |
121 output = '' | |
122 ) | |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
123 xml = XML('<root foo="bar"/>') |
832 | 124 self._test_eval( |
125 path = '@foo', | |
126 equiv = '<Path "attribute::foo">', | |
127 input = xml, | |
128 output = 'bar' | |
129 ) | |
130 self._test_eval( | |
131 path = './@foo', | |
132 equiv = '<Path "self::node()/attribute::foo">', | |
133 input = xml, | |
134 output = 'bar' | |
135 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
136 |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
137 def test_1step_text(self): |
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
138 xml = XML('<root>Hey</root>') |
832 | 139 self._test_eval( |
140 path = 'text()', | |
141 equiv = '<Path "child::text()">', | |
142 input = xml, | |
143 output = 'Hey' | |
144 ) | |
145 self._test_eval( | |
146 path = './text()', | |
147 equiv = '<Path "self::node()/child::text()">', | |
148 input = xml, | |
149 output = 'Hey' | |
150 ) | |
151 self._test_eval( | |
152 path = '//text()', | |
153 equiv = '<Path "descendant-or-self::text()">', | |
154 input = xml, | |
155 output = 'Hey' | |
156 ) | |
157 self._test_eval( | |
158 path = './/text()', | |
159 equiv = '<Path "self::node()/descendant-or-self::node()/child::text()">', | |
160 input = xml, | |
161 output = 'Hey' | |
162 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
163 |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
164 def test_2step(self): |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
165 xml = XML('<root><foo/><bar/></root>') |
832 | 166 self._test_eval('*', input=xml, output='<foo/><bar/>') |
167 self._test_eval('bar', input=xml, output='<bar/>') | |
168 self._test_eval('baz', input=xml, output='') | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
169 |
145
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
170 def test_2step_attribute(self): |
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
171 xml = XML('<elem class="x"><span id="joe">Hey Joe</span></elem>') |
832 | 172 self._test_eval('@*', input=xml, output='x') |
173 self._test_eval('./@*', input=xml, output='x') | |
174 self._test_eval('.//@*', input=xml, output='xjoe') | |
175 self._test_eval('*/@*', input=xml, output='joe') | |
145
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
176 |
215 | 177 xml = XML('<elem><foo id="1"/><foo id="2"/></elem>') |
832 | 178 self._test_eval('@*', input=xml, output='') |
179 self._test_eval('foo/@*', input=xml, output='12') | |
145
47bbd9d2a5af
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
138
diff
changeset
|
180 |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
181 def test_2step_complex(self): |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
182 xml = XML('<root><foo><bar/></foo></root>') |
832 | 183 self._test_eval( |
184 path = 'foo/bar', | |
185 equiv = '<Path "child::foo/child::bar">', | |
186 input = xml, | |
187 output = '<bar/>' | |
188 ) | |
189 self._test_eval( | |
190 path = './bar', | |
191 equiv = '<Path "self::node()/child::bar">', | |
192 input = xml, | |
193 output = '' | |
194 ) | |
195 self._test_eval( | |
196 path = 'foo/*', | |
197 equiv = '<Path "child::foo/child::*">', | |
198 input = xml, | |
199 output = '<bar/>' | |
200 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
201 xml = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>') |
832 | 202 self._test_eval( |
203 path = './bar', | |
204 equiv = '<Path "self::node()/child::bar">', | |
205 input = xml, | |
206 output = '<bar id="2"/>' | |
207 ) | |
833 | 208 xml = XML('''<table> |
209 <tr><td>1</td><td>One</td></tr> | |
210 <tr><td>2</td><td>Two</td></tr> | |
211 </table>''') | |
212 self._test_eval( | |
213 path = 'tr/td[1]', | |
214 input = xml, | |
215 output = '<td>1</td><td>2</td>' | |
216 ) | |
835
11a0cee8e8f5
Added XPath unit test for #271 (was already incorrectly committed in [1043], oops)
cmlenz
parents:
834
diff
changeset
|
217 xml = XML('''<ul> |
834 | 218 <li>item1 |
219 <ul><li>subitem11</li></ul> | |
220 </li> | |
221 <li>item2 | |
222 <ul><li>subitem21</li></ul> | |
223 </li> | |
224 </ul>''') | |
225 self._test_eval( | |
226 path = 'li[2]/ul', | |
227 input = xml, | |
228 output = '<ul><li>subitem21</li></ul>' | |
229 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
230 |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
231 def test_2step_text(self): |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
232 xml = XML('<root><item>Foo</item></root>') |
832 | 233 self._test_eval( |
234 path = 'item/text()', | |
235 equiv = '<Path "child::item/child::text()">', | |
236 input = xml, | |
237 output = 'Foo' | |
238 ) | |
239 self._test_eval( | |
240 path = '*/text()', | |
241 equiv = '<Path "child::*/child::text()">', | |
242 input = xml, | |
243 output = 'Foo' | |
244 ) | |
245 self._test_eval( | |
246 path = '//text()', | |
247 equiv = '<Path "descendant-or-self::text()">', | |
248 input = xml, | |
249 output = 'Foo' | |
250 ) | |
251 self._test_eval( | |
252 path = './text()', | |
253 equiv = '<Path "self::node()/child::text()">', | |
254 input = xml, | |
255 output = '' | |
256 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
257 xml = XML('<root><item>Foo</item><item>Bar</item></root>') |
832 | 258 self._test_eval( |
259 path = 'item/text()', | |
260 equiv = '<Path "child::item/child::text()">', | |
261 input = xml, | |
262 output = 'FooBar' | |
263 ) | |
264 xml = XML('<root><item><name>Foo</name><sub><name>Bar</name></sub></item></root>') | |
265 self._test_eval( | |
266 path = 'item/name/text()', | |
267 equiv = '<Path "child::item/child::name/child::text()">', | |
268 input = xml, | |
269 output = 'Foo' | |
270 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
271 |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
272 def test_3step(self): |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
273 xml = XML('<root><foo><bar/></foo></root>') |
832 | 274 self._test_eval( |
275 path = 'foo/*', | |
276 equiv = '<Path "child::foo/child::*">', | |
277 input = xml, | |
278 output = '<bar/>' | |
279 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
280 |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
281 def test_3step_complex(self): |
832 | 282 self._test_eval( |
283 path = '*/bar', | |
284 equiv = '<Path "child::*/child::bar">', | |
285 input = XML('<root><foo><bar/></foo></root>'), | |
286 output = '<bar/>' | |
287 ) | |
288 self._test_eval( | |
289 path = '//bar', | |
290 equiv = '<Path "descendant-or-self::bar">', | |
291 input = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>'), | |
292 output = '<bar id="1"/><bar id="2"/>' | |
293 ) | |
138 | 294 |
832 | 295 def test_3step_complex_text(self): |
296 xml = XML('<root><item><bar>Some text </bar><baz><bar>in here.</bar></baz></item></root>') | |
297 self._test_eval( | |
298 path = 'item/bar/text()', | |
299 equiv = '<Path "child::item/child::bar/child::text()">', | |
300 input = xml, | |
301 output = 'Some text ' | |
302 ) | |
303 self._test_eval( | |
304 path = 'item//bar/text()', | |
305 equiv = '<Path "child::item/descendant-or-self::node()/child::bar/child::text()">', | |
306 input = xml, | |
307 output = 'Some text in here.' | |
308 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
309 |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
310 def test_node_type_comment(self): |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
311 xml = XML('<root><!-- commented --></root>') |
832 | 312 self._test_eval( |
313 path = 'comment()', | |
314 equiv = '<Path "child::comment()">', | |
315 input = xml, | |
316 output = '<!-- commented -->' | |
317 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
318 |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
319 def test_node_type_text(self): |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
320 xml = XML('<root>Some text <br/>in here.</root>') |
832 | 321 self._test_eval( |
322 path = 'text()', | |
323 equiv = '<Path "child::text()">', | |
324 input = xml, | |
325 output = 'Some text in here.' | |
326 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
327 |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
328 def test_node_type_node(self): |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
329 xml = XML('<root>Some text <br/>in here.</root>') |
832 | 330 self._test_eval( |
331 path = 'node()', | |
332 equiv = '<Path "child::node()">', | |
333 input = xml, | |
334 output = 'Some text <br/>in here.' | |
335 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
336 |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
337 def test_node_type_processing_instruction(self): |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
338 xml = XML('<?python x = 2 * 3 ?><root><?php echo("x") ?></root>') |
832 | 339 self._test_eval( |
340 path = '//processing-instruction()', | |
341 equiv = '<Path "descendant-or-self::processing-instruction()">', | |
342 input = xml, | |
343 output = '<?python x = 2 * 3 ?><?php echo("x") ?>' | |
344 ) | |
345 self._test_eval( | |
346 path = 'processing-instruction()', | |
347 equiv = '<Path "child::processing-instruction()">', | |
348 input = xml, | |
349 output = '<?php echo("x") ?>' | |
350 ) | |
351 self._test_eval( | |
352 path = 'processing-instruction("php")', | |
353 equiv = '<Path "child::processing-instruction(\"php\")">', | |
354 input = xml, | |
355 output = '<?php echo("x") ?>' | |
356 ) | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
357 |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
358 def test_simple_union(self): |
259
fe8dbe9066c1
Fix bug in evaluating XPath expressions using the union operator `|`, which caused any path but the first to get out of sync with the event stream, and the whole thing returning too few results.
cmlenz
parents:
234
diff
changeset
|
359 xml = XML("""<body>1<br />2<br />3<br /></body>""") |
832 | 360 self._test_eval( |
361 path = '*|text()', | |
362 equiv = '<Path "child::*|child::text()">', | |
363 input = xml, | |
364 output = '1<br/>2<br/>3<br/>' | |
365 ) | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
366 |
121
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
367 def test_predicate_name(self): |
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
368 xml = XML('<root><foo/><bar/></root>') |
832 | 369 self._test_eval('*[name()="foo"]', input=xml, output='<foo/>') |
121
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
370 |
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
371 def test_predicate_localname(self): |
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
372 xml = XML('<root><foo xmlns="NS"/><bar/></root>') |
832 | 373 self._test_eval('*[local-name()="foo"]', input=xml, |
374 output='<foo xmlns="NS"/>') | |
121
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
375 |
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
376 def test_predicate_namespace(self): |
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
377 xml = XML('<root><foo xmlns="NS"/><bar/></root>') |
832 | 378 self._test_eval('*[namespace-uri()="NS"]', input=xml, |
379 output='<foo xmlns="NS"/>') | |
121
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
380 |
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
381 def test_predicate_not_name(self): |
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
382 xml = XML('<root><foo/><bar/></root>') |
832 | 383 self._test_eval('*[not(name()="foo")]', input=xml, |
384 output='<bar/>') | |
121
062e51ad7b19
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
111
diff
changeset
|
385 |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
386 def test_predicate_attr(self): |
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
387 xml = XML('<root><item/><item important="very"/></root>') |
832 | 388 self._test_eval('item[@important]', input=xml, |
389 output='<item important="very"/>') | |
390 self._test_eval('item[@important="very"]', input=xml, | |
391 output='<item important="very"/>') | |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
392 |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
393 def test_predicate_attr_equality(self): |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
394 xml = XML('<root><item/><item important="notso"/></root>') |
832 | 395 self._test_eval('item[@important="very"]', input=xml, output='') |
396 self._test_eval('item[@important!="very"]', input=xml, | |
397 output='<item/><item important="notso"/>') | |
162
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
398 |
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
399 def test_predicate_attr_greater_than(self): |
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
400 xml = XML('<root><item priority="3"/></root>') |
832 | 401 self._test_eval('item[@priority>3]', input=xml, output='') |
402 self._test_eval('item[@priority>2]', input=xml, | |
403 output='<item priority="3"/>') | |
162
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
404 |
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
405 def test_predicate_attr_less_than(self): |
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
406 xml = XML('<root><item priority="3"/></root>') |
832 | 407 self._test_eval('item[@priority<3]', input=xml, output='') |
408 self._test_eval('item[@priority<4]', input=xml, | |
409 output='<item priority="3"/>') | |
1 | 410 |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
411 def test_predicate_attr_and(self): |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
412 xml = XML('<root><item/><item important="very"/></root>') |
832 | 413 self._test_eval('item[@important and @important="very"]', |
414 input=xml, output='<item important="very"/>') | |
415 self._test_eval('item[@important and @important="notso"]', | |
416 input=xml, output='') | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
417 |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
418 def test_predicate_attr_or(self): |
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
419 xml = XML('<root><item/><item important="very"/></root>') |
832 | 420 self._test_eval('item[@urgent or @important]', input=xml, |
421 output='<item important="very"/>') | |
422 self._test_eval('item[@urgent or @notso]', input=xml, output='') | |
106
f9473bdc93b2
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
66
diff
changeset
|
423 |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
424 def test_predicate_boolean_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
425 xml = XML('<root><foo>bar</foo></root>') |
832 | 426 self._test_eval('*[boolean("")]', input=xml, output='') |
427 self._test_eval('*[boolean("yo")]', input=xml, | |
428 output='<foo>bar</foo>') | |
429 self._test_eval('*[boolean(0)]', input=xml, output='') | |
430 self._test_eval('*[boolean(42)]', input=xml, | |
431 output='<foo>bar</foo>') | |
432 self._test_eval('*[boolean(false())]', input=xml, output='') | |
433 self._test_eval('*[boolean(true())]', input=xml, | |
434 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
435 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
436 def test_predicate_ceil_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
437 xml = XML('<root><foo>bar</foo></root>') |
832 | 438 self._test_eval('*[ceiling("4.5")=5]', input=xml, |
439 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
440 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
441 def test_predicate_concat_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
442 xml = XML('<root><foo>bar</foo></root>') |
832 | 443 self._test_eval('*[name()=concat("f", "oo")]', input=xml, |
444 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
445 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
446 def test_predicate_contains_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
447 xml = XML('<root><foo>bar</foo></root>') |
832 | 448 self._test_eval('*[contains(name(), "oo")]', input=xml, |
449 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
450 |
534
57b5d5138f1a
Add XPath `matches()` function which, of course, supports the Python regular
athomas
parents:
413
diff
changeset
|
451 def test_predicate_matches_function(self): |
57b5d5138f1a
Add XPath `matches()` function which, of course, supports the Python regular
athomas
parents:
413
diff
changeset
|
452 xml = XML('<root><foo>bar</foo><bar>foo</bar></root>') |
832 | 453 self._test_eval('*[matches(name(), "foo|bar")]', input=xml, |
454 output='<foo>bar</foo><bar>foo</bar>') | |
534
57b5d5138f1a
Add XPath `matches()` function which, of course, supports the Python regular
athomas
parents:
413
diff
changeset
|
455 |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
456 def test_predicate_false_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
457 xml = XML('<root><foo>bar</foo></root>') |
832 | 458 self._test_eval('*[false()]', input=xml, output='') |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
459 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
460 def test_predicate_floor_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
461 xml = XML('<root><foo>bar</foo></root>') |
832 | 462 self._test_eval('*[floor("4.5")=4]', input=xml, |
463 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
464 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
465 def test_predicate_normalize_space_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
466 xml = XML('<root><foo>bar</foo></root>') |
832 | 467 self._test_eval('*[normalize-space(" foo bar ")="foo bar"]', |
468 input=xml, output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
469 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
470 def test_predicate_number_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
471 xml = XML('<root><foo>bar</foo></root>') |
832 | 472 self._test_eval('*[number("3.0")=3]', input=xml, |
473 output='<foo>bar</foo>') | |
474 self._test_eval('*[number("3.0")=3.0]', input=xml, | |
475 output='<foo>bar</foo>') | |
476 self._test_eval('*[number("0.1")=.1]', input=xml, | |
477 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
478 |
162
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
479 def test_predicate_round_function(self): |
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
480 xml = XML('<root><foo>bar</foo></root>') |
832 | 481 self._test_eval('*[round("4.4")=4]', input=xml, |
482 output='<foo>bar</foo>') | |
483 self._test_eval('*[round("4.6")=5]', input=xml, | |
484 output='<foo>bar</foo>') | |
162
456039594db9
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
155
diff
changeset
|
485 |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
486 def test_predicate_starts_with_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
487 xml = XML('<root><foo>bar</foo></root>') |
832 | 488 self._test_eval('*[starts-with(name(), "f")]', input=xml, |
489 output='<foo>bar</foo>') | |
490 self._test_eval('*[starts-with(name(), "b")]', input=xml, | |
491 output='') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
492 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
493 def test_predicate_string_length_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
494 xml = XML('<root><foo>bar</foo></root>') |
832 | 495 self._test_eval('*[string-length(name())=3]', input=xml, |
496 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
497 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
498 def test_predicate_substring_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
499 xml = XML('<root><foo>bar</foo></root>') |
832 | 500 self._test_eval('*[substring(name(), 1)="oo"]', input=xml, |
501 output='<foo>bar</foo>') | |
502 self._test_eval('*[substring(name(), 1, 1)="o"]', input=xml, | |
503 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
504 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
505 def test_predicate_substring_after_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
506 xml = XML('<root><foo>bar</foo></root>') |
832 | 507 self._test_eval('*[substring-after(name(), "f")="oo"]', input=xml, |
508 output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
509 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
510 def test_predicate_substring_before_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
511 xml = XML('<root><foo>bar</foo></root>') |
832 | 512 self._test_eval('*[substring-before(name(), "oo")="f"]', |
513 input=xml, output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
514 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
515 def test_predicate_translate_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
516 xml = XML('<root><foo>bar</foo></root>') |
832 | 517 self._test_eval('*[translate(name(), "fo", "ba")="baa"]', |
518 input=xml, output='<foo>bar</foo>') | |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
519 |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
520 def test_predicate_true_function(self): |
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
521 xml = XML('<root><foo>bar</foo></root>') |
832 | 522 self._test_eval('*[true()]', input=xml, output='<foo>bar</foo>') |
155
9a5aedda1099
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
523 |
179
13909179e5e1
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
164
diff
changeset
|
524 def test_predicate_variable(self): |
13909179e5e1
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
164
diff
changeset
|
525 xml = XML('<root><foo>bar</foo></root>') |
832 | 526 self._test_eval( |
527 path = '*[name()=$bar]', | |
528 input = xml, | |
529 output = '<foo>bar</foo>', | |
530 variables = {'bar': 'foo'} | |
531 ) | |
224
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
532 |
228
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
533 def test_predicate_position(self): |
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
534 xml = XML('<root><foo id="a1"/><foo id="a2"/><foo id="a3"/></root>') |
832 | 535 self._test_eval('*[2]', input=xml, output='<foo id="a2"/>') |
228
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
536 |
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
537 def test_predicate_attr_and_position(self): |
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
538 xml = XML('<root><foo/><foo id="a1"/><foo id="a2"/></root>') |
832 | 539 self._test_eval('*[@id][2]', input=xml, output='<foo id="a2"/>') |
228
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
540 |
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
541 def test_predicate_position_and_attr(self): |
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
542 xml = XML('<root><foo/><foo id="a1"/><foo id="a2"/></root>') |
832 | 543 self._test_eval('*[1][@id]', input=xml, output='') |
544 self._test_eval('*[2][@id]', input=xml, output='<foo id="a1"/>') | |
818 | 545 |
546 def test_predicate_advanced_position(self): | |
547 xml = XML('<root><a><b><c><d><e/></d></c></b></a></root>') | |
832 | 548 self._test_eval( 'descendant-or-self::*/' |
818 | 549 'descendant-or-self::*/' |
550 'descendant-or-self::*[2]/' | |
832 | 551 'self::*/descendant::*[3]', input=xml, |
552 output='<d><e/></d>') | |
818 | 553 |
554 def test_predicate_child_position(self): | |
555 xml = XML('\ | |
556 <root><a><b>1</b><b>2</b><b>3</b></a><a><b>4</b><b>5</b></a></root>') | |
832 | 557 self._test_eval('//a/b[2]', input=xml, output='<b>2</b><b>5</b>') |
558 self._test_eval('//a/b[3]', input=xml, output='<b>3</b>') | |
228
a5b38b459cbb
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
559 |
224
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
560 def test_name_with_namespace(self): |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
561 xml = XML('<root xmlns:f="FOO"><f:foo>bar</f:foo></root>') |
832 | 562 self._test_eval( |
563 path = 'f:foo', | |
564 equiv = '<Path "child::f:foo">', | |
565 input = xml, | |
566 output = '<foo xmlns="FOO">bar</foo>', | |
567 namespaces = {'f': 'FOO'} | |
568 ) | |
224
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
569 |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
570 def test_wildcard_with_namespace(self): |
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
571 xml = XML('<root xmlns:f="FOO"><f:foo>bar</f:foo></root>') |
832 | 572 self._test_eval( |
573 path = 'f:*', | |
574 equiv = '<Path "child::f:*">', | |
575 input = xml, | |
576 output = '<foo xmlns="FOO">bar</foo>', | |
577 namespaces = {'f': 'FOO'} | |
578 ) | |
224
90d62225f411
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
216
diff
changeset
|
579 |
384 | 580 def test_predicate_termination(self): |
581 """ | |
582 Verify that a patch matching the self axis with a predicate doesn't | |
583 cause an infinite loop. See <http://genshi.edgewall.org/ticket/82>. | |
584 """ | |
585 xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>') | |
832 | 586 self._test_eval('.[@flag="1"]/*', input=xml, |
587 output='<li>a</li><li>b</li>') | |
384 | 588 |
589 xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>') | |
832 | 590 self._test_eval('.[@flag="0"]/*', input=xml, output='') |
384 | 591 |
410
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
592 def test_attrname_with_namespace(self): |
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
593 xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>') |
832 | 594 self._test_eval('foo[@f:bar]', input=xml, |
595 output='<foo xmlns:ns1="FOO" ns1:bar="baz"/>', | |
596 namespaces={'f': 'FOO'}) | |
410
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
597 |
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
598 def test_attrwildcard_with_namespace(self): |
d14d89995c29
Improve the handling of namespaces in serialization.
cmlenz
parents:
384
diff
changeset
|
599 xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>') |
832 | 600 self._test_eval('foo[@f:*]', input=xml, |
601 output='<foo xmlns:ns1="FOO" ns1:bar="baz"/>', | |
602 namespaces={'f': 'FOO'}) | |
603 | |
818 | 604 def test_self_and_descendant(self): |
605 xml = XML('<root><foo/></root>') | |
832 | 606 self._test_eval('self::root', input=xml, output='<root><foo/></root>') |
607 self._test_eval('self::foo', input=xml, output='') | |
608 self._test_eval('descendant::root', input=xml, output='') | |
609 self._test_eval('descendant::foo', input=xml, output='<foo/>') | |
610 self._test_eval('descendant-or-self::root', input=xml, | |
611 output='<root><foo/></root>') | |
612 self._test_eval('descendant-or-self::foo', input=xml, output='<foo/>') | |
179
13909179e5e1
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
164
diff
changeset
|
613 |
818 | 614 def test_long_simple_paths(self): |
615 xml = XML('<root><a><b><a><d><a><b><a><b><a><b><a><c>!' | |
616 '</c></a></b></a></b></a></b></a></d></a></b></a></root>') | |
832 | 617 self._test_eval('//a/b/a/b/a/c', input=xml, output='<c>!</c>') |
618 self._test_eval('//a/b/a/c', input=xml, output='<c>!</c>') | |
619 self._test_eval('//a/c', input=xml, output='<c>!</c>') | |
620 self._test_eval('//c', input=xml, output='<c>!</c>') | |
818 | 621 # Please note that a//b is NOT the same as a/descendant::b |
622 # it is a/descendant-or-self::node()/b, which SimplePathStrategy | |
623 # does NOT support | |
832 | 624 self._test_eval('a/b/descendant::a/c', input=xml, output='<c>!</c>') |
625 self._test_eval('a/b/descendant::a/d/descendant::a/c', | |
626 input=xml, output='<c>!</c>') | |
627 self._test_eval('a/b/descendant::a/d/a/c', input=xml, output='') | |
628 self._test_eval('//d/descendant::b/descendant::b/descendant::b' | |
629 '/descendant::c', input=xml, output='<c>!</c>') | |
630 self._test_eval('//d/descendant::b/descendant::b/descendant::b' | |
631 '/descendant::b/descendant::c', input=xml, | |
632 output='') | |
633 | |
1043
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
634 def test_attr_selection(self): |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
635 xml = XML('<root><foo bar="abc"></foo></root>') |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
636 path = Path('foo/@bar') |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
637 result = path.select(xml) |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
638 self.assertEqual(list(result), [ |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
639 Attrs([(QName('bar'), u'abc')]) |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
640 ]) |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
641 |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
642 def test_attr_selection_with_namespace(self): |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
643 xml = XML( |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
644 '<root xmlns:ns1="http://example.com">' |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
645 '<foo ns1:bar="abc"></foo>' |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
646 '</root>') |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
647 path = Path('foo/@ns1:bar') |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
648 result = path.select(xml, namespaces={'ns1': 'http://example.com'}) |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
649 self.assertEqual(list(result), [ |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
650 Attrs([(QName('http://example.com}bar'), u'abc')]) |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
651 ]) |
a21009a2bc3a
Return correct value and properly namespaced attribute name when matching namespaced attributes with XPath expressions (fixes #572; thanks to Olemis Lang <olemis+trac@gmail.com> for bug report and suggestion for fix).
hodgestar
parents:
864
diff
changeset
|
652 |
818 | 653 def _test_support(self, strategy_class, text): |
654 path = PathParser(text, None, -1).parse()[0] | |
655 return strategy_class.supports(path) | |
832 | 656 |
818 | 657 def test_simple_strategy_support(self): |
658 self.assert_(self._test_support(SimplePathStrategy, 'a/b')) | |
659 self.assert_(self._test_support(SimplePathStrategy, 'self::a/b')) | |
660 self.assert_(self._test_support(SimplePathStrategy, 'descendant::a/b')) | |
661 self.assert_(self._test_support(SimplePathStrategy, | |
662 'descendant-or-self::a/b')) | |
663 self.assert_(self._test_support(SimplePathStrategy, '//a/b')) | |
664 self.assert_(self._test_support(SimplePathStrategy, 'a/@b')) | |
665 self.assert_(self._test_support(SimplePathStrategy, 'a/text()')) | |
666 | |
667 # a//b is a/descendant-or-self::node()/b | |
668 self.assert_(not self._test_support(SimplePathStrategy, 'a//b')) | |
669 self.assert_(not self._test_support(SimplePathStrategy, 'node()/@a')) | |
670 self.assert_(not self._test_support(SimplePathStrategy, '@a')) | |
671 self.assert_(not self._test_support(SimplePathStrategy, 'foo:bar')) | |
672 self.assert_(not self._test_support(SimplePathStrategy, 'a/@foo:bar')) | |
1 | 673 |
832 | 674 def _test_strategies(self, input, path, output, |
675 namespaces=None, variables=None): | |
676 for strategy in self.strategies: | |
677 if not strategy.supports(path): | |
678 continue | |
679 s = strategy(path) | |
680 rendered = FakePath(s).select(input, namespaces=namespaces, | |
864 | 681 variables=variables) \ |
682 .render(encoding=None) | |
832 | 683 msg = 'Bad render using %s strategy' % str(strategy) |
684 msg += '\nExpected:\t%r' % output | |
685 msg += '\nRendered:\t%r' % rendered | |
686 self.assertEqual(output, rendered, msg) | |
687 | |
688 def _test_eval(self, path, equiv=None, input=None, output='', | |
689 namespaces=None, variables=None): | |
690 path = Path(path) | |
691 if equiv is not None: | |
692 self.assertEqual(equiv, repr(path)) | |
693 | |
694 if input is None: | |
695 return | |
696 | |
697 rendered = path.select(input, namespaces=namespaces, | |
864 | 698 variables=variables).render(encoding=None) |
832 | 699 msg = 'Bad output using whole path' |
700 msg += '\nExpected:\t%r' % output | |
701 msg += '\nRendered:\t%r' % rendered | |
702 self.assertEqual(output, rendered, msg) | |
703 | |
704 if len(path.paths) == 1: | |
705 self._test_strategies(input, path.paths[0], output, | |
706 namespaces=namespaces, variables=variables) | |
707 | |
708 | |
1 | 709 def suite(): |
710 suite = unittest.TestSuite() | |
111
2368c3becc52
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
711 suite.addTest(doctest.DocTestSuite(Path.__module__)) |
26
3c1a022be04c
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
1
diff
changeset
|
712 suite.addTest(unittest.makeSuite(PathTestCase, 'test')) |
1 | 713 return suite |
714 | |
832 | 715 |
1 | 716 if __name__ == '__main__': |
717 unittest.main(defaultTest='suite') |