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