Mercurial > genshi > genshi-test
annotate genshi/path.py @ 500:0742f421caba experimental-inline
Merged revisions 487-603 via svnmerge from
http://svn.edgewall.org/repos/genshi/trunk
author | cmlenz |
---|---|
date | Fri, 01 Jun 2007 17:21:47 +0000 |
parents | 55cf81951686 |
children | 1837f39efd6f |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
66
822089ae65ce
Switch copyright to Edgewall and URLs to markup.edgewall.org.
cmlenz
parents:
61
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 |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
14 """Basic support for evaluating XPath expressions against streams. |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
15 |
230 | 16 >>> from genshi.input import XML |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
17 >>> doc = XML('''<doc> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
18 ... <items count="2"> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
19 ... <item status="new"> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
20 ... <summary>Foo</summary> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
21 ... </item> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
22 ... <item status="closed"> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
23 ... <summary>Bar</summary> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
24 ... </item> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
25 ... </items> |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
26 ... </doc>''') |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
27 >>> print doc.select('items/item[@status="closed"]/summary/text()') |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
28 Bar |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
29 |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
30 Because the XPath engine operates on markup streams (as opposed to tree |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
31 structures), it only implements a subset of the full XPath 1.0 language. |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
32 """ |
1 | 33 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
34 from math import ceil, floor |
1 | 35 import re |
36 | |
230 | 37 from genshi.core import Stream, Attrs, Namespace, QName |
38 from genshi.core import START, END, TEXT, COMMENT, PI | |
1 | 39 |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
40 __all__ = ['Path', 'PathSyntaxError'] |
500 | 41 __docformat__ = 'restructuredtext en' |
1 | 42 |
43 | |
114 | 44 class Axis(object): |
45 """Defines constants for the various supported XPath axes.""" | |
46 | |
47 ATTRIBUTE = 'attribute' | |
48 CHILD = 'child' | |
49 DESCENDANT = 'descendant' | |
50 DESCENDANT_OR_SELF = 'descendant-or-self' | |
51 SELF = 'self' | |
52 | |
53 def forname(cls, name): | |
54 """Return the axis constant for the given name, or `None` if no such | |
55 axis was defined. | |
56 """ | |
57 return getattr(cls, name.upper().replace('-', '_'), None) | |
58 forname = classmethod(forname) | |
59 | |
60 | |
61 ATTRIBUTE = Axis.ATTRIBUTE | |
62 CHILD = Axis.CHILD | |
63 DESCENDANT = Axis.DESCENDANT | |
64 DESCENDANT_OR_SELF = Axis.DESCENDANT_OR_SELF | |
65 SELF = Axis.SELF | |
66 | |
67 | |
1 | 68 class Path(object): |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
69 """Implements basic XPath support on streams. |
1 | 70 |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
71 Instances of this class represent a "compiled" XPath expression, and provide |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
72 methods for testing the path against a stream, as well as extracting a |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
73 substream matching that path. |
1 | 74 """ |
75 | |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
76 def __init__(self, text, filename=None, lineno=-1): |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
77 """Create the path object from a string. |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
78 |
500 | 79 :param text: the path expression |
80 :param filename: the name of the file in which the path expression was | |
81 found (used in error messages) | |
82 :param lineno: the line on which the expression was found | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
83 """ |
1 | 84 self.source = text |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
85 self.paths = PathParser(text, filename, lineno).parse() |
1 | 86 |
87 def __repr__(self): | |
137 | 88 paths = [] |
89 for path in self.paths: | |
90 steps = [] | |
91 for axis, nodetest, predicates in path: | |
92 steps.append('%s::%s' % (axis, nodetest)) | |
93 for predicate in predicates: | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
94 steps[-1] += '[%s]' % predicate |
137 | 95 paths.append('/'.join(steps)) |
96 return '<%s "%s">' % (self.__class__.__name__, '|'.join(paths)) | |
1 | 97 |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
98 def select(self, stream, namespaces=None, variables=None): |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
99 """Returns a substream of the given stream that matches the path. |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
100 |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
101 If there are no matches, this method returns an empty stream. |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
102 |
230 | 103 >>> from genshi.input import XML |
33 | 104 >>> xml = XML('<root><elem><child>Text</child></elem></root>') |
61 | 105 |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
106 >>> print Path('.//child').select(xml) |
33 | 107 <child>Text</child> |
108 | |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
109 >>> print Path('.//child/text()').select(xml) |
33 | 110 Text |
111 | |
500 | 112 :param stream: the stream to select from |
113 :param namespaces: (optional) a mapping of namespace prefixes to URIs | |
114 :param variables: (optional) a mapping of variable names to values | |
115 :return: the substream matching the path, or an empty stream | |
116 :rtype: `Stream` | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
117 """ |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
118 if namespaces is None: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
119 namespaces = {} |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
120 if variables is None: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
121 variables = {} |
1 | 122 stream = iter(stream) |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
123 def _generate(): |
1 | 124 test = self.test() |
305 | 125 for event in stream: |
126 result = test(event, namespaces, variables) | |
1 | 127 if result is True: |
305 | 128 yield event |
330
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
129 if event[0] is START: |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
130 depth = 1 |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
131 while depth > 0: |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
132 subevent = stream.next() |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
133 if subevent[0] is START: |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
134 depth += 1 |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
135 elif subevent[0] is END: |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
136 depth -= 1 |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
137 yield subevent |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
138 test(subevent, namespaces, variables, |
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
139 updateonly=True) |
1 | 140 elif result: |
141 yield result | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
142 return Stream(_generate()) |
1 | 143 |
38
fec9f4897415
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:
37
diff
changeset
|
144 def test(self, ignore_context=False): |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
145 """Returns a function that can be used to track whether the path matches |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
146 a specific stream event. |
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
147 |
500 | 148 The function returned expects the positional arguments ``event``, |
149 ``namespaces`` and ``variables``. The first is a stream event, while the | |
305 | 150 latter two are a mapping of namespace prefixes to URIs, and a mapping |
306 | 151 of variable names to values, respectively. In addition, the function |
500 | 152 accepts an ``updateonly`` keyword argument that default to ``False``. If |
153 it is set to ``True``, the function only updates its internal state, | |
306 | 154 but does not perform any tests or return a result. |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
155 |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
156 If the path matches the event, the function returns the match (for |
500 | 157 example, a `START` or `TEXT` event.) Otherwise, it returns ``None``. |
33 | 158 |
230 | 159 >>> from genshi.input import XML |
33 | 160 >>> xml = XML('<root><elem><child id="1"/></elem><child id="2"/></root>') |
161 >>> test = Path('child').test() | |
305 | 162 >>> for event in xml: |
163 ... if test(event, {}, {}): | |
395 | 164 ... print event[0], repr(event[1]) |
165 START (QName(u'child'), Attrs([(QName(u'id'), u'2')])) | |
500 | 166 |
167 :param ignore_context: if `True`, the path is interpreted like a pattern | |
168 in XSLT, meaning for example that it will match | |
169 at any depth | |
170 :return: a function that can be used to test individual events in a | |
171 stream against the path | |
172 :rtype: ``function`` | |
26
039fc5b87405
* Split out the XPath tests into a separate `unittest`-based file.
cmlenz
parents:
25
diff
changeset
|
173 """ |
333
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
174 paths = [(p, len(p), [0], [], [0] * len(p)) for p in [ |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
175 (ignore_context and [_DOTSLASHSLASH] or []) + p for p in self.paths |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
176 ]] |
1 | 177 |
306 | 178 def _test(event, namespaces, variables, updateonly=False): |
330
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
179 kind, data, pos = event[:3] |
259
6f11ad260890
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:
250
diff
changeset
|
180 retval = None |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
181 for steps, size, cursors, cutoff, counter in paths: |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
182 # Manage the stack that tells us "where we are" in the stream |
211
0a14c2a06be3
Fix another regression introduced in [258]: some kinds of cascaded match templates were broken, for example in the TurboGears example app.
cmlenz
parents:
179
diff
changeset
|
183 if kind is END: |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
184 if cursors: |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
185 cursors.pop() |
211
0a14c2a06be3
Fix another regression introduced in [258]: some kinds of cascaded match templates were broken, for example in the TurboGears example app.
cmlenz
parents:
179
diff
changeset
|
186 continue |
223 | 187 elif kind is START: |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
188 cursors.append(cursors and cursors[-1] or 0) |
259
6f11ad260890
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:
250
diff
changeset
|
189 |
306 | 190 if updateonly or retval or not cursors: |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
191 continue |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
192 cursor = cursors[-1] |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
193 depth = len(cursors) |
1 | 194 |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
195 if cutoff and depth + int(kind is not START) > cutoff[0]: |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
196 continue |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
197 |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
198 ctxtnode = not ignore_context and kind is START \ |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
199 and depth == 2 |
259
6f11ad260890
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:
250
diff
changeset
|
200 matched = None |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
201 while 1: |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
202 # Fetch the next location step |
137 | 203 axis, nodetest, predicates = steps[cursor] |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
204 |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
205 # If this is the start event for the context node, and the |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
206 # axis of the location step doesn't include the current |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
207 # element, skip the test |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
208 if ctxtnode and (axis is CHILD or axis is DESCENDANT): |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
209 break |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
210 |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
211 # Is this the last step of the location path? |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
212 last_step = cursor + 1 == size |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
213 |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
214 # Perform the actual node test |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
215 matched = nodetest(kind, data, pos, namespaces, variables) |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
216 |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
217 # The node test matched |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
218 if matched: |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
219 |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
220 # Check all the predicates for this step |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
221 if predicates: |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
222 for predicate in predicates: |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
223 pretval = predicate(kind, data, pos, namespaces, |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
224 variables) |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
225 if type(pretval) is float: |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
226 counter[cursor] += 1 |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
227 if counter[cursor] != int(pretval): |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
228 pretval = False |
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
229 if not pretval: |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
230 matched = None |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
231 break |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
232 |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
233 # Both the node test and the predicates matched |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
234 if matched: |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
235 if last_step: |
217
d8b195b22a44
Fix `py:match` directive which would screw up in some scenarios due to incorrect handling of the substream. Closes #49.
cmlenz
parents:
216
diff
changeset
|
236 if not ctxtnode or kind is not START \ |
d8b195b22a44
Fix `py:match` directive which would screw up in some scenarios due to incorrect handling of the substream. Closes #49.
cmlenz
parents:
216
diff
changeset
|
237 or axis is ATTRIBUTE or axis is SELF: |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
238 retval = matched |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
239 elif not ctxtnode or axis is SELF \ |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
240 or axis is DESCENDANT_OR_SELF: |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
241 cursor += 1 |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
242 cursors[-1] = cursor |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
243 cutoff[:] = [] |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
244 |
333
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
245 if kind is START: |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
246 if last_step and not (axis is DESCENDANT or |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
247 axis is DESCENDANT_OR_SELF): |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
248 cutoff[:] = [depth] |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
249 |
333
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
250 elif steps[cursor][0] is ATTRIBUTE: |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
251 # If the axis of the next location step is the |
395 | 252 # attribute axis, we need to move on to processing |
253 # that step without waiting for the next markup | |
254 # event | |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
255 continue |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
256 |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
257 # We're done with this step if it's the last step or the |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
258 # axis isn't "self" |
395 | 259 if not matched or last_step or not ( |
260 axis is SELF or axis is DESCENDANT_OR_SELF): | |
216
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
261 break |
0a01371cecbc
Many fixes to XPath evaluation. Among other things, this should get rid of the bug that attributes were getting ?pulled up? by `py:match` directives using `py:attrs="select('@*')"` (see #50).
cmlenz
parents:
215
diff
changeset
|
262 |
333
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
263 if (retval or not matched) and kind is START and \ |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
264 not (axis is DESCENDANT or axis is DESCENDANT_OR_SELF): |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
265 # If this step is not a closure, it cannot be matched until |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
266 # the current element is closed... so we need to move the |
114 | 267 # cursor back to the previous closure and retest that |
268 # against the current element | |
333
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
269 backsteps = [(i, k, d, p) for i, (k, d, p) |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
270 in enumerate(steps[:cursor]) |
215 | 271 if k is DESCENDANT or k is DESCENDANT_OR_SELF] |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
272 backsteps.reverse() |
333
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
273 for cursor, axis, nodetest, predicates in backsteps: |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
274 if nodetest(kind, data, pos, namespaces, variables): |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
275 cutoff[:] = [] |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
276 break |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
277 cursors[-1] = cursor |
1 | 278 |
259
6f11ad260890
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:
250
diff
changeset
|
279 return retval |
1 | 280 |
281 return _test | |
282 | |
283 | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
284 class PathSyntaxError(Exception): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
285 """Exception raised when an XPath expression is syntactically incorrect.""" |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
286 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
287 def __init__(self, message, filename=None, lineno=-1, offset=-1): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
288 if filename: |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
289 message = '%s (%s, line %d)' % (message, filename, lineno) |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
290 Exception.__init__(self, message) |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
291 self.filename = filename |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
292 self.lineno = lineno |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
293 self.offset = offset |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
294 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
295 |
137 | 296 class PathParser(object): |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
297 """Tokenizes and parses an XPath expression.""" |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
298 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
299 _QUOTES = (("'", "'"), ('"', '"')) |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
300 _TOKENS = ('::', ':', '..', '.', '//', '/', '[', ']', '()', '(', ')', '@', |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
301 '=', '!=', '!', '|', ',', '>=', '>', '<=', '<', '$') |
163
9df6f057efd3
Support for XPath number literals including decimal places.
cmlenz
parents:
162
diff
changeset
|
302 _tokenize = re.compile('("[^"]*")|(\'[^\']*\')|((?:\d+)?\.\d+)|(%s)|([^%s\s]+)|\s+' % ( |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
303 '|'.join([re.escape(t) for t in _TOKENS]), |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
304 ''.join([re.escape(t[0]) for t in _TOKENS]))).findall |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
305 |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
306 def __init__(self, text, filename=None, lineno=-1): |
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
307 self.filename = filename |
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
308 self.lineno = lineno |
163
9df6f057efd3
Support for XPath number literals including decimal places.
cmlenz
parents:
162
diff
changeset
|
309 self.tokens = filter(None, [dqstr or sqstr or number or token or name |
9df6f057efd3
Support for XPath number literals including decimal places.
cmlenz
parents:
162
diff
changeset
|
310 for dqstr, sqstr, number, token, name in |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
311 self._tokenize(text)]) |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
312 self.pos = 0 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
313 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
314 # Tokenizer |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
315 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
316 at_end = property(lambda self: self.pos == len(self.tokens) - 1) |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
317 cur_token = property(lambda self: self.tokens[self.pos]) |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
318 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
319 def next_token(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
320 self.pos += 1 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
321 return self.tokens[self.pos] |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
322 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
323 def peek_token(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
324 if not self.at_end: |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
325 return self.tokens[self.pos + 1] |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
326 return None |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
327 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
328 # Recursive descent parser |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
329 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
330 def parse(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
331 """Parses the XPath expression and returns a list of location path |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
332 tests. |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
333 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
334 For union expressions (such as `*|text()`), this function returns one |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
335 test for each operand in the union. For patch expressions that don't |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
336 use the union operator, the function always returns a list of size 1. |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
337 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
338 Each path test in turn is a sequence of tests that correspond to the |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
339 location steps, each tuples of the form `(axis, testfunc, predicates)` |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
340 """ |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
341 paths = [self._location_path()] |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
342 while self.cur_token == '|': |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
343 self.next_token() |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
344 paths.append(self._location_path()) |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
345 if not self.at_end: |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
346 raise PathSyntaxError('Unexpected token %r after end of expression' |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
347 % self.cur_token, self.filename, self.lineno) |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
348 return paths |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
349 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
350 def _location_path(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
351 steps = [] |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
352 while True: |
215 | 353 if self.cur_token.startswith('/'): |
354 if self.cur_token == '//': | |
355 steps.append((DESCENDANT_OR_SELF, NodeTest(), [])) | |
356 elif not steps: | |
357 raise PathSyntaxError('Absolute location paths not ' | |
358 'supported', self.filename, | |
359 self.lineno) | |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
360 self.next_token() |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
361 |
137 | 362 axis, nodetest, predicates = self._location_step() |
363 if not axis: | |
145
56d534eb53f9
* Fix error in expression evaluation when the expression evaluates to an iterable that does not produce event tuples.
cmlenz
parents:
139
diff
changeset
|
364 axis = CHILD |
137 | 365 steps.append((axis, nodetest, predicates)) |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
366 |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
367 if self.at_end or not self.cur_token.startswith('/'): |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
368 break |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
369 |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
370 return steps |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
371 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
372 def _location_step(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
373 if self.cur_token == '@': |
114 | 374 axis = ATTRIBUTE |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
375 self.next_token() |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
376 elif self.cur_token == '.': |
114 | 377 axis = SELF |
137 | 378 elif self.cur_token == '..': |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
379 raise PathSyntaxError('Unsupported axis "parent"', self.filename, |
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
380 self.lineno) |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
381 elif self.peek_token() == '::': |
114 | 382 axis = Axis.forname(self.cur_token) |
383 if axis is None: | |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
384 raise PathSyntaxError('Unsupport axis "%s"' % axis, |
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
385 self.filename, self.lineno) |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
386 self.next_token() |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
387 self.next_token() |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
388 else: |
137 | 389 axis = None |
390 nodetest = self._node_test(axis or CHILD) | |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
391 predicates = [] |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
392 while self.cur_token == '[': |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
393 predicates.append(self._predicate()) |
137 | 394 return axis, nodetest, predicates |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
395 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
396 def _node_test(self, axis=None): |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
397 test = prefix = None |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
398 next_token = self.peek_token() |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
399 if next_token in ('(', '()'): # Node type test |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
400 test = self._node_type() |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
401 |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
402 elif next_token == ':': # Namespace prefix |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
403 prefix = self.cur_token |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
404 self.next_token() |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
405 localname = self.next_token() |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
406 if localname == '*': |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
407 test = QualifiedPrincipalTypeTest(axis, prefix) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
408 else: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
409 test = QualifiedNameTest(axis, prefix, localname) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
410 |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
411 else: # Name test |
137 | 412 if self.cur_token == '*': |
413 test = PrincipalTypeTest(axis) | |
414 elif self.cur_token == '.': | |
415 test = NodeTest() | |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
416 else: |
137 | 417 test = LocalNameTest(axis, self.cur_token) |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
418 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
419 if not self.at_end: |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
420 self.next_token() |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
421 return test |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
422 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
423 def _node_type(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
424 name = self.cur_token |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
425 self.next_token() |
137 | 426 |
427 args = [] | |
428 if self.cur_token != '()': | |
429 # The processing-instruction() function optionally accepts the | |
430 # name of the PI as argument, which must be a literal string | |
431 self.next_token() # ( | |
432 if self.cur_token != ')': | |
433 string = self.cur_token | |
434 if (string[0], string[-1]) in self._QUOTES: | |
435 string = string[1:-1] | |
436 args.append(string) | |
437 | |
438 cls = _nodetest_map.get(name) | |
439 if not cls: | |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
440 raise PathSyntaxError('%s() not allowed here' % name, self.filename, |
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
441 self.lineno) |
137 | 442 return cls(*args) |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
443 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
444 def _predicate(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
445 assert self.cur_token == '[' |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
446 self.next_token() |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
447 expr = self._or_expr() |
121
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
114
diff
changeset
|
448 if self.cur_token != ']': |
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
114
diff
changeset
|
449 raise PathSyntaxError('Expected "]" to close predicate, ' |
139
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
450 'but found "%s"' % self.cur_token, |
54131cbb91a5
Implement position reporting for XPath syntax errors. Closes #20.
cmlenz
parents:
137
diff
changeset
|
451 self.filename, self.lineno) |
111
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
452 if not self.at_end: |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
453 self.next_token() |
8a4d9064f363
Some fixes and more unit tests for the XPath engine.
cmlenz
parents:
106
diff
changeset
|
454 return expr |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
455 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
456 def _or_expr(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
457 expr = self._and_expr() |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
458 while self.cur_token == 'or': |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
459 self.next_token() |
137 | 460 expr = OrOperator(expr, self._and_expr()) |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
461 return expr |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
462 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
463 def _and_expr(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
464 expr = self._equality_expr() |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
465 while self.cur_token == 'and': |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
466 self.next_token() |
137 | 467 expr = AndOperator(expr, self._equality_expr()) |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
468 return expr |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
469 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
470 def _equality_expr(self): |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
471 expr = self._relational_expr() |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
472 while self.cur_token in ('=', '!='): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
473 op = _operator_map[self.cur_token] |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
474 self.next_token() |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
475 expr = op(expr, self._relational_expr()) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
476 return expr |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
477 |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
478 def _relational_expr(self): |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
479 expr = self._primary_expr() |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
480 while self.cur_token in ('>', '>=', '<', '>='): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
481 op = _operator_map[self.cur_token] |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
482 self.next_token() |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
483 expr = op(expr, self._primary_expr()) |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
484 return expr |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
485 |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
486 def _primary_expr(self): |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
487 token = self.cur_token |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
488 if len(token) > 1 and (token[0], token[-1]) in self._QUOTES: |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
489 self.next_token() |
137 | 490 return StringLiteral(token[1:-1]) |
163
9df6f057efd3
Support for XPath number literals including decimal places.
cmlenz
parents:
162
diff
changeset
|
491 elif token[0].isdigit() or token[0] == '.': |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
492 self.next_token() |
137 | 493 return NumberLiteral(float(token)) |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
494 elif token == '$': |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
495 token = self.next_token() |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
496 self.next_token() |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
497 return VariableReference(token) |
121
22a7080ed242
Added support for the XPath functions `name()`, `namespace-uri()`, `local-name()`, and `not()`.
cmlenz
parents:
114
diff
changeset
|
498 elif not self.at_end and self.peek_token().startswith('('): |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
499 return self._function_call() |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
500 else: |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
501 axis = None |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
502 if token == '@': |
114 | 503 axis = ATTRIBUTE |
106
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
504 self.next_token() |
61fa4cadb766
Complete rewrite of the XPath parsing, which was a mess before. Closes #19.
cmlenz
parents:
77
diff
changeset
|
505 return self._node_test(axis) |
137 | 506 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
507 def _function_call(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
508 name = self.cur_token |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
509 if self.next_token() == '()': |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
510 args = [] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
511 else: |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
512 assert self.cur_token == '(' |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
513 self.next_token() |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
514 args = [self._or_expr()] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
515 while self.cur_token == ',': |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
516 self.next_token() |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
517 args.append(self._or_expr()) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
518 if not self.cur_token == ')': |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
519 raise PathSyntaxError('Expected ")" to close function argument ' |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
520 'list, but found "%s"' % self.cur_token, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
521 self.filename, self.lineno) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
522 self.next_token() |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
523 cls = _function_map.get(name) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
524 if not cls: |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
525 raise PathSyntaxError('Unsupported function "%s"' % name, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
526 self.filename, self.lineno) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
527 return cls(*args) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
528 |
137 | 529 |
530 # Node tests | |
531 | |
532 class PrincipalTypeTest(object): | |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
533 """Node test that matches any event with the given principal type.""" |
137 | 534 __slots__ = ['principal_type'] |
535 def __init__(self, principal_type): | |
536 self.principal_type = principal_type | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
537 def __call__(self, kind, data, pos, namespaces, variables): |
137 | 538 if kind is START: |
539 if self.principal_type is ATTRIBUTE: | |
540 return data[1] or None | |
541 else: | |
542 return True | |
543 def __repr__(self): | |
544 return '*' | |
545 | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
546 class QualifiedPrincipalTypeTest(object): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
547 """Node test that matches any event with the given principal type in a |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
548 specific namespace.""" |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
549 __slots__ = ['principal_type', 'prefix'] |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
550 def __init__(self, principal_type, prefix): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
551 self.principal_type = principal_type |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
552 self.prefix = prefix |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
553 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
554 namespace = Namespace(namespaces.get(self.prefix)) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
555 if kind is START: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
556 if self.principal_type is ATTRIBUTE and data[1]: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
557 return Attrs([(name, value) for name, value in data[1] |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
558 if name in namespace]) or None |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
559 else: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
560 return data[0] in namespace |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
561 def __repr__(self): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
562 return '%s:*' % self.prefix |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
563 |
137 | 564 class LocalNameTest(object): |
395 | 565 """Node test that matches any event with the given principal type and |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
566 local name. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
567 """ |
137 | 568 __slots__ = ['principal_type', 'name'] |
569 def __init__(self, principal_type, name): | |
570 self.principal_type = principal_type | |
571 self.name = name | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
572 def __call__(self, kind, data, pos, namespaces, variables): |
137 | 573 if kind is START: |
574 if self.principal_type is ATTRIBUTE and self.name in data[1]: | |
234 | 575 return data[1].get(self.name) |
137 | 576 else: |
577 return data[0].localname == self.name | |
578 def __repr__(self): | |
579 return self.name | |
580 | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
581 class QualifiedNameTest(object): |
395 | 582 """Node test that matches any event with the given principal type and |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
583 qualified name. |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
584 """ |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
585 __slots__ = ['principal_type', 'prefix', 'name'] |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
586 def __init__(self, principal_type, prefix, name): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
587 self.principal_type = principal_type |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
588 self.prefix = prefix |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
589 self.name = name |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
590 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
591 qname = QName('%s}%s' % (namespaces.get(self.prefix), self.name)) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
592 if kind is START: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
593 if self.principal_type is ATTRIBUTE and qname in data[1]: |
234 | 594 return data[1].get(qname) |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
595 else: |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
596 return data[0] == qname |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
597 def __repr__(self): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
598 return '%s:%s' % (self.prefix, self.name) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
599 |
137 | 600 class CommentNodeTest(object): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
601 """Node test that matches any comment events.""" |
137 | 602 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
603 def __call__(self, kind, data, pos, namespaces, variables): |
330
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
604 return kind is COMMENT |
137 | 605 def __repr__(self): |
606 return 'comment()' | |
607 | |
608 class NodeTest(object): | |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
609 """Node test that matches any node.""" |
137 | 610 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
611 def __call__(self, kind, data, pos, namespaces, variables): |
137 | 612 if kind is START: |
613 return True | |
614 return kind, data, pos | |
615 def __repr__(self): | |
616 return 'node()' | |
617 | |
618 class ProcessingInstructionNodeTest(object): | |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
619 """Node test that matches any processing instruction event.""" |
137 | 620 __slots__ = ['target'] |
621 def __init__(self, target=None): | |
622 self.target = target | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
623 def __call__(self, kind, data, pos, namespaces, variables): |
330
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
624 return kind is PI and (not self.target or data[0] == self.target) |
137 | 625 def __repr__(self): |
626 arg = '' | |
627 if self.target: | |
628 arg = '"' + self.target + '"' | |
629 return 'processing-instruction(%s)' % arg | |
630 | |
631 class TextNodeTest(object): | |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
632 """Node test that matches any text event.""" |
137 | 633 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
634 def __call__(self, kind, data, pos, namespaces, variables): |
330
1dbeaef463e7
XPath tests should never return event tuples, just values or booleans.
cmlenz
parents:
326
diff
changeset
|
635 return kind is TEXT |
137 | 636 def __repr__(self): |
637 return 'text()' | |
638 | |
639 _nodetest_map = {'comment': CommentNodeTest, 'node': NodeTest, | |
640 'processing-instruction': ProcessingInstructionNodeTest, | |
641 'text': TextNodeTest} | |
642 | |
643 # Functions | |
644 | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
645 class Function(object): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
646 """Base class for function nodes in XPath expressions.""" |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
647 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
648 class BooleanFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
649 """The `boolean` function, which converts its argument to a boolean |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
650 value. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
651 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
652 __slots__ = ['expr'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
653 def __init__(self, expr): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
654 self.expr = expr |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
655 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
656 val = self.expr(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
657 return bool(val) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
658 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
659 return 'boolean(%r)' % self.expr |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
660 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
661 class CeilingFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
662 """The `ceiling` function, which returns the nearest lower integer number |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
663 for the given number. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
664 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
665 __slots__ = ['number'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
666 def __init__(self, number): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
667 self.number = number |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
668 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
669 number = self.number(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
670 return ceil(float(number)) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
671 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
672 return 'ceiling(%r)' % self.number |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
673 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
674 class ConcatFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
675 """The `concat` function, which concatenates (joins) the variable number of |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
676 strings it gets as arguments. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
677 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
678 __slots__ = ['exprs'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
679 def __init__(self, *exprs): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
680 self.exprs = exprs |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
681 def __call__(self, kind, data, pos, namespaces, variables): |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
682 strings = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
683 for item in [expr(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
684 for expr in self.exprs]: |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
685 strings.append(item) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
686 return u''.join(strings) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
687 def __repr__(self): |
169 | 688 return 'concat(%s)' % ', '.join([repr(expr) for expr in self.exprs]) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
689 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
690 class ContainsFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
691 """The `contains` function, which returns whether a string contains a given |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
692 substring. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
693 """ |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
694 __slots__ = ['string1', 'string2'] |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
695 def __init__(self, string1, string2): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
696 self.string1 = string1 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
697 self.string2 = string2 |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
698 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
699 string1 = self.string1(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
700 string2 = self.string2(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
701 return string2 in string1 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
702 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
703 return 'contains(%r, %r)' % (self.string1, self.string2) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
704 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
705 class FalseFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
706 """The `false` function, which always returns the boolean `false` value.""" |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
707 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
708 def __call__(self, kind, data, pos, namespaces, variables): |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
709 return False |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
710 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
711 return 'false()' |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
712 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
713 class FloorFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
714 """The `ceiling` function, which returns the nearest higher integer number |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
715 for the given number. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
716 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
717 __slots__ = ['number'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
718 def __init__(self, number): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
719 self.number = number |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
720 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
721 number = self.number(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
722 return floor(float(number)) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
723 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
724 return 'floor(%r)' % self.number |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
725 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
726 class LocalNameFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
727 """The `local-name` function, which returns the local name of the current |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
728 element. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
729 """ |
137 | 730 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
731 def __call__(self, kind, data, pos, namespaces, variables): |
137 | 732 if kind is START: |
234 | 733 return data[0].localname |
137 | 734 def __repr__(self): |
735 return 'local-name()' | |
736 | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
737 class NameFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
738 """The `name` function, which returns the qualified name of the current |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
739 element. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
740 """ |
137 | 741 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
742 def __call__(self, kind, data, pos, namespaces, variables): |
137 | 743 if kind is START: |
234 | 744 return data[0] |
137 | 745 def __repr__(self): |
746 return 'name()' | |
747 | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
748 class NamespaceUriFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
749 """The `namespace-uri` function, which returns the namespace URI of the |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
750 current element. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
751 """ |
137 | 752 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
753 def __call__(self, kind, data, pos, namespaces, variables): |
137 | 754 if kind is START: |
234 | 755 return data[0].namespace |
137 | 756 def __repr__(self): |
757 return 'namespace-uri()' | |
758 | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
759 class NotFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
760 """The `not` function, which returns the negated boolean value of its |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
761 argument. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
762 """ |
137 | 763 __slots__ = ['expr'] |
764 def __init__(self, expr): | |
765 self.expr = expr | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
766 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
767 return not self.expr(kind, data, pos, namespaces, variables) |
137 | 768 def __repr__(self): |
769 return 'not(%s)' % self.expr | |
770 | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
771 class NormalizeSpaceFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
772 """The `normalize-space` function, which removes leading and trailing |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
773 whitespace in the given string, and replaces multiple adjacent whitespace |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
774 characters inside the string with a single space. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
775 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
776 __slots__ = ['expr'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
777 _normalize = re.compile(r'\s{2,}').sub |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
778 def __init__(self, expr): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
779 self.expr = expr |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
780 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
781 string = self.expr(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
782 return self._normalize(' ', string.strip()) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
783 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
784 return 'normalize-space(%s)' % repr(self.expr) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
785 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
786 class NumberFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
787 """The `number` function that converts its argument to a number.""" |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
788 __slots__ = ['expr'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
789 def __init__(self, expr): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
790 self.expr = expr |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
791 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
792 val = self.expr(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
793 return float(val) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
794 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
795 return 'number(%r)' % self.expr |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
796 |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
797 class RoundFunction(Function): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
798 """The `round` function, which returns the nearest integer number for the |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
799 given number. |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
800 """ |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
801 __slots__ = ['number'] |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
802 def __init__(self, number): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
803 self.number = number |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
804 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
805 number = self.number(kind, data, pos, namespaces, variables) |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
806 return round(float(number)) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
807 def __repr__(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
808 return 'round(%r)' % self.number |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
809 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
810 class StartsWithFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
811 """The `starts-with` function that returns whether one string starts with |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
812 a given substring. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
813 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
814 __slots__ = ['string1', 'string2'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
815 def __init__(self, string1, string2): |
282
db5bdeca9192
Fix `starts-with()` XPath function so that it actually compares the two strings. Closes #61.
cmlenz
parents:
259
diff
changeset
|
816 self.string1 = string1 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
817 self.string2 = string2 |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
818 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
819 string1 = self.string1(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
820 string2 = self.string2(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
821 return string1.startswith(string2) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
822 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
823 return 'starts-with(%r, %r)' % (self.string1, self.string2) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
824 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
825 class StringLengthFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
826 """The `string-length` function that returns the length of the given |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
827 string. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
828 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
829 __slots__ = ['expr'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
830 def __init__(self, expr): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
831 self.expr = expr |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
832 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
833 string = self.expr(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
834 return len(string) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
835 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
836 return 'string-length(%r)' % self.expr |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
837 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
838 class SubstringFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
839 """The `substring` function that returns the part of a string that starts |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
840 at the given offset, and optionally limited to the given length. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
841 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
842 __slots__ = ['string', 'start', 'length'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
843 def __init__(self, string, start, length=None): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
844 self.string = string |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
845 self.start = start |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
846 self.length = length |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
847 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
848 string = self.string(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
849 start = self.start(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
850 length = 0 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
851 if self.length is not None: |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
852 length = self.length(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
853 return string[int(start):len(string) - int(length)] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
854 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
855 if self.length is not None: |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
856 return 'substring(%r, %r, %r)' % (self.string, self.start, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
857 self.length) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
858 else: |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
859 return 'substring(%r, %r)' % (self.string, self.start) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
860 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
861 class SubstringAfterFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
862 """The `substring-after` function that returns the part of a string that |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
863 is found after the given substring. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
864 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
865 __slots__ = ['string1', 'string2'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
866 def __init__(self, string1, string2): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
867 self.string1 = string1 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
868 self.string2 = string2 |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
869 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
870 string1 = self.string1(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
871 string2 = self.string2(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
872 index = string1.find(string2) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
873 if index >= 0: |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
874 return string1[index + len(string2):] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
875 return u'' |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
876 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
877 return 'substring-after(%r, %r)' % (self.string1, self.string2) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
878 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
879 class SubstringBeforeFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
880 """The `substring-before` function that returns the part of a string that |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
881 is found before the given substring. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
882 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
883 __slots__ = ['string1', 'string2'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
884 def __init__(self, string1, string2): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
885 self.string1 = string1 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
886 self.string2 = string2 |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
887 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
888 string1 = self.string1(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
889 string2 = self.string2(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
890 index = string1.find(string2) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
891 if index >= 0: |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
892 return string1[:index] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
893 return u'' |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
894 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
895 return 'substring-after(%r, %r)' % (self.string1, self.string2) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
896 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
897 class TranslateFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
898 """The `translate` function that translates a set of characters in a |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
899 string to target set of characters. |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
900 """ |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
901 __slots__ = ['string', 'fromchars', 'tochars'] |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
902 def __init__(self, string, fromchars, tochars): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
903 self.string = string |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
904 self.fromchars = fromchars |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
905 self.tochars = tochars |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
906 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
907 string = self.string(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
908 fromchars = self.fromchars(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
909 tochars = self.tochars(kind, data, pos, namespaces, variables) |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
910 table = dict(zip([ord(c) for c in fromchars], |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
911 [ord(c) for c in tochars])) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
912 return string.translate(table) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
913 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
914 return 'translate(%r, %r, %r)' % (self.string, self.fromchars, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
915 self.tochars) |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
916 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
917 class TrueFunction(Function): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
918 """The `true` function, which always returns the boolean `true` value.""" |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
919 __slots__ = [] |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
920 def __call__(self, kind, data, pos, namespaces, variables): |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
921 return True |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
922 def __repr__(self): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
923 return 'true()' |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
924 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
925 _function_map = {'boolean': BooleanFunction, 'ceiling': CeilingFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
926 'concat': ConcatFunction, 'contains': ContainsFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
927 'false': FalseFunction, 'floor': FloorFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
928 'local-name': LocalNameFunction, 'name': NameFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
929 'namespace-uri': NamespaceUriFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
930 'normalize-space': NormalizeSpaceFunction, 'not': NotFunction, |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
931 'number': NumberFunction, 'round': RoundFunction, |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
932 'starts-with': StartsWithFunction, |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
933 'string-length': StringLengthFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
934 'substring': SubstringFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
935 'substring-after': SubstringAfterFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
936 'substring-before': SubstringBeforeFunction, |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
937 'translate': TranslateFunction, 'true': TrueFunction} |
137 | 938 |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
939 # Literals & Variables |
137 | 940 |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
941 class Literal(object): |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
942 """Abstract base class for literal nodes.""" |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
943 |
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
944 class StringLiteral(Literal): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
945 """A string literal node.""" |
137 | 946 __slots__ = ['text'] |
947 def __init__(self, text): | |
948 self.text = text | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
949 def __call__(self, kind, data, pos, namespaces, variables): |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
950 return self.text |
137 | 951 def __repr__(self): |
952 return '"%s"' % self.text | |
953 | |
155
50d4b08017df
* String literals in XPath expressions that contains spaces are now tokenizes correctly.
cmlenz
parents:
145
diff
changeset
|
954 class NumberLiteral(Literal): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
955 """A number literal node.""" |
137 | 956 __slots__ = ['number'] |
957 def __init__(self, number): | |
958 self.number = number | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
959 def __call__(self, kind, data, pos, namespaces, variables): |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
960 return self.number |
137 | 961 def __repr__(self): |
962 return str(self.number) | |
963 | |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
964 class VariableReference(Literal): |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
965 """A variable reference node.""" |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
966 __slots__ = ['name'] |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
967 def __init__(self, name): |
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
968 self.name = name |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
969 def __call__(self, kind, data, pos, namespaces, variables): |
228
f79b20a50919
Add support for position predicates in XPath expressions.
cmlenz
parents:
224
diff
changeset
|
970 return variables.get(self.name) |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
971 def __repr__(self): |
215 | 972 return str(self.name) |
179
a2e0a7986d19
Implemented support for XPath variables in predicates (#31).
cmlenz
parents:
169
diff
changeset
|
973 |
137 | 974 # Operators |
975 | |
976 class AndOperator(object): | |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
977 """The boolean operator `and`.""" |
137 | 978 __slots__ = ['lval', 'rval'] |
979 def __init__(self, lval, rval): | |
980 self.lval = lval | |
981 self.rval = rval | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
982 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
983 lval = self.lval(kind, data, pos, namespaces, variables) |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
984 if not lval: |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
985 return False |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
986 rval = self.rval(kind, data, pos, namespaces, variables) |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
987 return bool(rval) |
137 | 988 def __repr__(self): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
989 return '%s and %s' % (self.lval, self.rval) |
137 | 990 |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
991 class EqualsOperator(object): |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
992 """The equality operator `=`.""" |
137 | 993 __slots__ = ['lval', 'rval'] |
994 def __init__(self, lval, rval): | |
995 self.lval = lval | |
996 self.rval = rval | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
997 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
998 lval = self.lval(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
999 rval = self.rval(kind, data, pos, namespaces, variables) |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1000 return lval == rval |
137 | 1001 def __repr__(self): |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1002 return '%s=%s' % (self.lval, self.rval) |
137 | 1003 |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1004 class NotEqualsOperator(object): |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1005 """The equality operator `!=`.""" |
137 | 1006 __slots__ = ['lval', 'rval'] |
1007 def __init__(self, lval, rval): | |
1008 self.lval = lval | |
1009 self.rval = rval | |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1010 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1011 lval = self.lval(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1012 rval = self.rval(kind, data, pos, namespaces, variables) |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1013 return lval != rval |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1014 def __repr__(self): |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1015 return '%s!=%s' % (self.lval, self.rval) |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1016 |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1017 class OrOperator(object): |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1018 """The boolean operator `or`.""" |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1019 __slots__ = ['lval', 'rval'] |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1020 def __init__(self, lval, rval): |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1021 self.lval = lval |
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1022 self.rval = rval |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1023 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1024 lval = self.lval(kind, data, pos, namespaces, variables) |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1025 if lval: |
137 | 1026 return True |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1027 rval = self.rval(kind, data, pos, namespaces, variables) |
161
a25f9fc5787d
Various docstring additions and other cosmetic changes.
cmlenz
parents:
156
diff
changeset
|
1028 return bool(rval) |
137 | 1029 def __repr__(self): |
1030 return '%s or %s' % (self.lval, self.rval) | |
1031 | |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1032 class GreaterThanOperator(object): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1033 """The relational operator `>` (greater than).""" |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1034 __slots__ = ['lval', 'rval'] |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1035 def __init__(self, lval, rval): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1036 self.lval = lval |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1037 self.rval = rval |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1038 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1039 lval = self.lval(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1040 rval = self.rval(kind, data, pos, namespaces, variables) |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1041 return float(lval) > float(rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1042 def __repr__(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1043 return '%s>%s' % (self.lval, self.rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1044 |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1045 class GreaterThanOrEqualOperator(object): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1046 """The relational operator `>=` (greater than or equal).""" |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1047 __slots__ = ['lval', 'rval'] |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1048 def __init__(self, lval, rval): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1049 self.lval = lval |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1050 self.rval = rval |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1051 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1052 lval = self.lval(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1053 rval = self.rval(kind, data, pos, namespaces, variables) |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1054 return float(lval) >= float(rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1055 def __repr__(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1056 return '%s>=%s' % (self.lval, self.rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1057 |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1058 class LessThanOperator(object): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1059 """The relational operator `<` (less than).""" |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1060 __slots__ = ['lval', 'rval'] |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1061 def __init__(self, lval, rval): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1062 self.lval = lval |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1063 self.rval = rval |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1064 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1065 lval = self.lval(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1066 rval = self.rval(kind, data, pos, namespaces, variables) |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1067 return float(lval) < float(rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1068 def __repr__(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1069 return '%s<%s' % (self.lval, self.rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1070 |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1071 class LessThanOrEqualOperator(object): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1072 """The relational operator `<=` (less than or equal).""" |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1073 __slots__ = ['lval', 'rval'] |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1074 def __init__(self, lval, rval): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1075 self.lval = lval |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1076 self.rval = rval |
224
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1077 def __call__(self, kind, data, pos, namespaces, variables): |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1078 lval = self.lval(kind, data, pos, namespaces, variables) |
e4dad1145f84
Implement support for namespace prefixes in XPath expressions.
cmlenz
parents:
223
diff
changeset
|
1079 rval = self.rval(kind, data, pos, namespaces, variables) |
162
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1080 return float(lval) <= float(rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1081 def __repr__(self): |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1082 return '%s<=%s' % (self.lval, self.rval) |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1083 |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1084 _operator_map = {'=': EqualsOperator, '!=': NotEqualsOperator, |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1085 '>': GreaterThanOperator, '>=': GreaterThanOrEqualOperator, |
f767cf98e3e3
Implement the XPath relational operators and the `round()` function.
cmlenz
parents:
161
diff
changeset
|
1086 '<': LessThanOperator, '>=': LessThanOrEqualOperator} |
333
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
1087 |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
1088 |
b70563ade748
Fix XPath traversal in match templates. Previously, `div/p` would be treated the same as `div//p`, i.e. it would match all descendants and not just the immediate children.
cmlenz
parents:
330
diff
changeset
|
1089 _DOTSLASHSLASH = (DESCENDANT_OR_SELF, PrincipalTypeTest(None), ()) |