Revision 76
Added by Aaron Marcuse-Kubitza about 13 years ago
xpath.py | ||
---|---|---|
34 | 34 |
len(elem.attrs[0]) == 1: return elem.attrs[0] |
35 | 35 |
else: return None |
36 | 36 |
|
37 |
class XpathParser(Parser): |
|
38 |
def _main(self): |
|
39 |
self._match_str('/') # optional leading / |
|
40 |
return self._path() |
|
37 |
def parse(str_): |
|
38 |
parser = Parser(str_) |
|
41 | 39 |
|
42 |
def _path(self):
|
|
40 |
def _path(): |
|
43 | 41 |
tree = [] |
44 | 42 |
trailing_slash = False |
45 | 43 |
while True: |
46 | 44 |
# Split path |
47 |
if self._match_str('{'):
|
|
45 |
if parser.str_('{'):
|
|
48 | 46 |
paths = [] |
49 | 47 |
while True: |
50 |
paths.append(tree + self._path())
|
|
51 |
if not self._match_str(','): break
|
|
52 |
self._match_str('}', required=True)
|
|
48 |
paths.append(tree + _path()) |
|
49 |
if not parser.str_(','): break
|
|
50 |
parser.str_('}', required=True)
|
|
53 | 51 |
tree = paths[0] # just use first subpath for now |
54 | 52 |
break # nothing allowed after split path |
55 | 53 |
|
56 |
elem = XpathElem(is_attr=self._match_str('@'),
|
|
57 |
name=self._match_re(r'[\w.*]+', required=True))
|
|
54 |
elem = XpathElem(is_attr=parser.str_('@'),
|
|
55 |
name=parser.re(r'[\w.*]+', required=True))
|
|
58 | 56 |
|
59 | 57 |
# Attrs |
60 |
if self._match_str('['):
|
|
58 |
if parser.str_('['):
|
|
61 | 59 |
elem.attrs = [] |
62 | 60 |
while True: |
63 |
path = self._path()
|
|
64 |
if self._match_str('='):
|
|
65 |
set_value(path, self._match_re(r'[\w.|]*'))
|
|
61 |
path = _path() |
|
62 |
if parser.str_('='):
|
|
63 |
set_value(path, parser.re(r'[\w.|]*'))
|
|
66 | 64 |
elem.attrs.append(path) |
67 |
if not self._match_str(','): break
|
|
68 |
self._match_str(']', required=True)
|
|
65 |
if not parser.str_(','): break
|
|
66 |
parser.str_(']', required=True)
|
|
69 | 67 |
|
70 |
elem.is_ptr = self._match_str('->')
|
|
68 |
elem.is_ptr = parser.str_('->')
|
|
71 | 69 |
tree.append(elem) |
72 | 70 |
|
73 | 71 |
# Lookahead assertion |
74 |
if self._match_str('('):
|
|
75 |
self._match_str('/', required=True) # next / is inside ()
|
|
76 |
path = self._path()
|
|
77 |
self._match_str(')', required=True)
|
|
72 |
if parser.str_('('):
|
|
73 |
parser.str_('/', required=True) # next / is inside ()
|
|
74 |
path = _path() |
|
75 |
parser.str_(')', required=True)
|
|
78 | 76 |
elem.attrs.append(path) |
79 | 77 |
tree += path |
80 | 78 |
|
81 |
if not self._match_str('/'): break
|
|
79 |
if not parser.str_('/'): break
|
|
82 | 80 |
|
83 | 81 |
# Expand * abbrs |
84 | 82 |
for i in reversed(xrange(len(tree))): |
... | ... | |
93 | 91 |
except IndexError: pass # no replacement elem |
94 | 92 |
|
95 | 93 |
return tree |
94 |
|
|
95 |
parser.str_('/') # optional leading / |
|
96 |
path = _path() |
|
97 |
parser.end() |
|
98 |
return path |
|
96 | 99 |
|
97 |
def parse(string): return XpathParser(string).parse() |
|
98 |
|
|
99 | 100 |
instance_level = 1 |
100 | 101 |
|
101 | 102 |
def obj(path): |
Also available in: Unified diff
Refactored xpath.parse() to use a nested function instead of a class extending Parser