annotate genshi/path.py @ 234:39c424b80edd trunk

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