annotate markup/path.py @ 224:e4dad1145f84

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