~0x44/nova/extdoc

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/twisted/words/xish/xpath.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.words.test.test_xpath -*-
 
2
#
 
3
# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
 
4
# See LICENSE for details.
 
5
 
 
6
"""
 
7
XPath query support.
 
8
 
 
9
This module provides L{XPathQuery} to match
 
10
L{domish.Element<twisted.words.xish.domish.Element>} instances against
 
11
XPath-like expressions.
 
12
"""
 
13
 
 
14
try:
 
15
    import cStringIO as StringIO
 
16
except ImportError:
 
17
    import StringIO
 
18
 
 
19
class LiteralValue(str):
 
20
    def value(self, elem):
 
21
        return self
 
22
 
 
23
 
 
24
class IndexValue:
 
25
    def __init__(self, index):
 
26
        self.index = int(index) - 1
 
27
 
 
28
    def value(self, elem):
 
29
        return elem.children[self.index]
 
30
 
 
31
 
 
32
class AttribValue:
 
33
    def __init__(self, attribname):
 
34
        self.attribname = attribname
 
35
        if self.attribname == "xmlns":
 
36
            self.value = self.value_ns
 
37
 
 
38
    def value_ns(self, elem):
 
39
        return elem.uri
 
40
 
 
41
    def value(self, elem):
 
42
        if self.attribname in elem.attributes:
 
43
            return elem.attributes[self.attribname]
 
44
        else:
 
45
            return None
 
46
 
 
47
 
 
48
class CompareValue:
 
49
    def __init__(self, lhs, op, rhs):
 
50
        self.lhs = lhs
 
51
        self.rhs = rhs
 
52
        if op == "=":
 
53
            self.value = self._compareEqual
 
54
        else:
 
55
            self.value = self._compareNotEqual
 
56
 
 
57
    def _compareEqual(self, elem):
 
58
        return self.lhs.value(elem) == self.rhs.value(elem)
 
59
 
 
60
    def _compareNotEqual(self, elem):
 
61
        return self.lhs.value(elem) != self.rhs.value(elem)
 
62
 
 
63
 
 
64
class BooleanValue:
 
65
    """
 
66
    Provide boolean XPath expression operators.
 
67
 
 
68
    @ivar lhs: Left hand side expression of the operator.
 
69
    @ivar op: The operator. One of C{'and'}, C{'or'}.
 
70
    @ivar rhs: Right hand side expression of the operator.
 
71
    @ivar value: Reference to the method that will calculate the value of
 
72
                 this expression given an element.
 
73
    """
 
74
    def __init__(self, lhs, op, rhs):
 
75
        self.lhs = lhs
 
76
        self.rhs = rhs
 
77
        if op == "and":
 
78
            self.value = self._booleanAnd
 
79
        else:
 
80
            self.value = self._booleanOr
 
81
 
 
82
    def _booleanAnd(self, elem):
 
83
        """
 
84
        Calculate boolean and of the given expressions given an element.
 
85
 
 
86
        @param elem: The element to calculate the value of the expression from.
 
87
        """
 
88
        return self.lhs.value(elem) and self.rhs.value(elem)
 
89
 
 
90
    def _booleanOr(self, elem):
 
91
        """
 
92
        Calculate boolean or of the given expressions given an element.
 
93
 
 
94
        @param elem: The element to calculate the value of the expression from.
 
95
        """
 
96
        return self.lhs.value(elem) or self.rhs.value(elem)
 
97
 
 
98
 
 
99
def Function(fname):
 
100
    """
 
101
    Internal method which selects the function object
 
102
    """
 
103
    klassname = "_%s_Function" % fname
 
104
    c = globals()[klassname]()
 
105
    return c
 
106
 
 
107
 
 
108
class _not_Function:
 
109
    def __init__(self):
 
110
        self.baseValue = None
 
111
 
 
112
    def setParams(self, baseValue):
 
113
        self.baseValue = baseValue
 
114
 
 
115
    def value(self, elem):
 
116
        return not self.baseValue.value(elem)
 
117
 
 
118
 
 
119
class _text_Function:
 
120
    def setParams(self):
 
121
        pass
 
122
 
 
123
    def value(self, elem):
 
124
        return str(elem)
 
125
 
 
126
 
 
127
class _Location:
 
128
    def __init__(self):
 
129
        self.predicates = []
 
130
        self.elementName  = None
 
131
        self.childLocation = None
 
132
 
 
133
    def matchesPredicates(self, elem):
 
134
        if self.elementName != None and self.elementName != elem.name:
 
135
            return 0
 
136
 
 
137
        for p in self.predicates:
 
138
            if not p.value(elem):
 
139
                return 0
 
140
 
 
141
        return 1
 
142
 
 
143
    def matches(self, elem):
 
144
        if not self.matchesPredicates(elem):
 
145
            return 0
 
146
 
 
147
        if self.childLocation != None:
 
148
            for c in elem.elements():
 
149
                if self.childLocation.matches(c):
 
150
                    return 1
 
151
        else:
 
152
            return 1
 
153
 
 
154
        return 0
 
155
 
 
156
    def queryForString(self, elem, resultbuf):
 
157
        if not self.matchesPredicates(elem):
 
158
            return
 
159
 
 
160
        if self.childLocation != None:
 
161
            for c in elem.elements():
 
162
                self.childLocation.queryForString(c, resultbuf)
 
163
        else:
 
164
            resultbuf.write(str(elem))
 
165
 
 
166
    def queryForNodes(self, elem, resultlist):
 
167
        if not self.matchesPredicates(elem):
 
168
            return
 
169
 
 
170
        if self.childLocation != None:
 
171
            for c in elem.elements():
 
172
                self.childLocation.queryForNodes(c, resultlist)
 
173
        else:
 
174
            resultlist.append(elem)
 
175
 
 
176
    def queryForStringList(self, elem, resultlist):
 
177
        if not self.matchesPredicates(elem):
 
178
            return
 
179
 
 
180
        if self.childLocation != None:
 
181
            for c in elem.elements():
 
182
                self.childLocation.queryForStringList(c, resultlist)
 
183
        else:
 
184
            for c in elem.children:
 
185
                if isinstance(c, (str, unicode)):
 
186
                    resultlist.append(c)
 
187
 
 
188
 
 
189
class _AnyLocation:
 
190
    def __init__(self):
 
191
        self.predicates = []
 
192
        self.elementName = None
 
193
        self.childLocation = None
 
194
 
 
195
    def matchesPredicates(self, elem):
 
196
        for p in self.predicates:
 
197
            if not p.value(elem):
 
198
                return 0
 
199
        return 1
 
200
 
 
201
    def listParents(self, elem, parentlist):
 
202
        if elem.parent != None:
 
203
            self.listParents(elem.parent, parentlist)
 
204
        parentlist.append(elem.name)
 
205
 
 
206
    def isRootMatch(self, elem):
 
207
        if (self.elementName == None or self.elementName == elem.name) and \
 
208
           self.matchesPredicates(elem):
 
209
            if self.childLocation != None:
 
210
                for c in elem.elements():
 
211
                    if self.childLocation.matches(c):
 
212
                        return True
 
213
            else:
 
214
                return True
 
215
        return False
 
216
 
 
217
    def findFirstRootMatch(self, elem):
 
218
        if (self.elementName == None or self.elementName == elem.name) and \
 
219
           self.matchesPredicates(elem):
 
220
            # Thus far, the name matches and the predicates match,
 
221
            # now check into the children and find the first one
 
222
            # that matches the rest of the structure
 
223
            # the rest of the structure
 
224
            if self.childLocation != None:
 
225
                for c in elem.elements():
 
226
                    if self.childLocation.matches(c):
 
227
                        return c
 
228
                return None
 
229
            else:
 
230
                # No children locations; this is a match!
 
231
                return elem
 
232
        else:
 
233
            # Ok, predicates or name didn't match, so we need to start
 
234
            # down each child and treat it as the root and try
 
235
            # again
 
236
            for c in elem.elements():
 
237
                if self.matches(c):
 
238
                    return c
 
239
            # No children matched...
 
240
            return None
 
241
 
 
242
    def matches(self, elem):
 
243
        if self.isRootMatch(elem):
 
244
            return True
 
245
        else:
 
246
            # Ok, initial element isn't an exact match, walk
 
247
            # down each child and treat it as the root and try
 
248
            # again
 
249
            for c in elem.elements():
 
250
                if self.matches(c):
 
251
                    return True
 
252
            # No children matched...
 
253
            return False
 
254
 
 
255
    def queryForString(self, elem, resultbuf):
 
256
        raise NotImplementedError(
 
257
            "queryForString is not implemented for any location")
 
258
 
 
259
    def queryForNodes(self, elem, resultlist):
 
260
        # First check to see if _this_ element is a root
 
261
        if self.isRootMatch(elem):
 
262
            resultlist.append(elem)
 
263
 
 
264
        # Now check each child
 
265
        for c in elem.elements():
 
266
            self.queryForNodes(c, resultlist)
 
267
 
 
268
 
 
269
    def queryForStringList(self, elem, resultlist):
 
270
        if self.isRootMatch(elem):
 
271
            for c in elem.children:
 
272
                if isinstance(c, (str, unicode)):
 
273
                    resultlist.append(c)
 
274
        for c in elem.elements():
 
275
            self.queryForStringList(c, resultlist)
 
276
 
 
277
 
 
278
class XPathQuery:
 
279
    def __init__(self, queryStr):
 
280
        self.queryStr = queryStr
 
281
        from twisted.words.xish.xpathparser import parse
 
282
        self.baseLocation = parse('XPATH', queryStr)
 
283
 
 
284
    def __hash__(self):
 
285
        return self.queryStr.__hash__()
 
286
 
 
287
    def matches(self, elem):
 
288
        return self.baseLocation.matches(elem)
 
289
 
 
290
    def queryForString(self, elem):
 
291
        result = StringIO.StringIO()
 
292
        self.baseLocation.queryForString(elem, result)
 
293
        return result.getvalue()
 
294
 
 
295
    def queryForNodes(self, elem):
 
296
        result = []
 
297
        self.baseLocation.queryForNodes(elem, result)
 
298
        if len(result) == 0:
 
299
            return None
 
300
        else:
 
301
            return result
 
302
 
 
303
    def queryForStringList(self, elem):
 
304
        result = []
 
305
        self.baseLocation.queryForStringList(elem, result)
 
306
        if len(result) == 0:
 
307
            return None
 
308
        else:
 
309
            return result
 
310
 
 
311
 
 
312
__internedQueries = {}
 
313
 
 
314
def internQuery(queryString):
 
315
    if queryString not in __internedQueries:
 
316
        __internedQueries[queryString] = XPathQuery(queryString)
 
317
    return __internedQueries[queryString]
 
318
 
 
319
 
 
320
def matches(xpathstr, elem):
 
321
    return internQuery(xpathstr).matches(elem)
 
322
 
 
323
 
 
324
def queryForStringList(xpathstr, elem):
 
325
    return internQuery(xpathstr).queryForStringList(elem)
 
326
 
 
327
 
 
328
def queryForString(xpathstr, elem):
 
329
    return internQuery(xpathstr).queryForString(elem)
 
330
 
 
331
 
 
332
def queryForNodes(xpathstr, elem):
 
333
    return internQuery(xpathstr).queryForNodes(elem)