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