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