Revision 25
Added by Aaron Marcuse-Kubitza about 13 years ago
xpath.py | ||
---|---|---|
19 | 19 |
def __repr__(self): |
20 | 20 |
str_ = '' |
21 | 21 |
if self.is_attr: str_ += '@' |
22 |
str_ += self.name+repr(self.attrs)+'='+repr(self.value) |
|
22 |
str_ += self.name |
|
23 |
if self.attrs != []: str_ += repr(self.attrs) |
|
24 |
if self.value != None: str_ += '='+repr(self.value) |
|
23 | 25 |
if self.is_ptr: str_ += '->' |
24 | 26 |
return str_ |
25 | 27 |
|
... | ... | |
36 | 38 |
|
37 | 39 |
def _path(self): |
38 | 40 |
tree = [] |
41 |
fork_idx = None |
|
42 |
elem_idx = 0 |
|
39 | 43 |
while True: |
40 | 44 |
elem = XpathElem(is_attr=self._match_str('@'), name=self._fields()) |
41 | 45 |
if self._match_str('['): |
42 | 46 |
elem.attrs = self._attrs() |
43 | 47 |
self._match_str(']', required=True) |
44 | 48 |
elem.is_ptr = self._match_str('->') |
49 |
if not elem.is_ptr and self._match_str('!'): fork_idx = elem_idx |
|
45 | 50 |
tree.append(elem) |
46 | 51 |
if not self._match_str('/'): break |
52 |
elem_idx += 1 |
|
53 |
# Add lookahead assertion for rest of path |
|
54 |
if fork_idx != None: tree[fork_idx].attrs.append(tree[fork_idx+1:]) |
|
47 | 55 |
return tree |
48 | 56 |
|
49 | 57 |
def _fields(self): |
... | ... | |
116 | 124 |
|
117 | 125 |
# Follow pointer |
118 | 126 |
if elem.is_ptr: |
119 |
target = deepcopy(path[elem_idx+1:]) # rest of path
|
|
120 |
attrs = target[types_id_level].attrs
|
|
127 |
path = deepcopy(path[elem_idx+1:]) # rest of path
|
|
128 |
attrs = path[types_id_level].attrs
|
|
121 | 129 |
if len(attrs) >= 1 and value(attrs[0]) == None: |
122 | 130 |
# backward (child-to-parent) pointer with target ID attr |
123 | 131 |
set_value(attrs[0], xml_util.get_id(node)) |
124 | 132 |
else: # forward (parent-to-child) pointer |
125 | 133 |
id_ = xml_util.value(node) |
126 |
if id_ == None: |
|
134 |
obj_path = path[:types_id_level+1] # target object |
|
135 |
if id_ == None or get(doc, obj_path, False, True) == None: |
|
136 |
# no target or target attrs don't match |
|
127 | 137 |
if not create: return None |
138 |
|
|
128 | 139 |
# Use last target object's ID + 1 |
129 |
obj = get(doc, target[:types_id_level+1], False, True) |
|
130 |
if obj != None: id_ = str(int(xml_util.get_id(obj)) + 1) |
|
140 |
last_path = deepcopy(obj_path) |
|
141 |
last_path[-1].attrs = [] # just get by tag name |
|
142 |
last = get(doc, last_path, False, True) |
|
143 |
if last != None: id_ = str(int(xml_util.get_id(last)) + 1) |
|
131 | 144 |
else: id_ = '0' |
145 |
|
|
146 |
# Will append if target attrs didn't match. Place ! in XPath |
|
147 |
# after element to fork at to avoid this. |
|
132 | 148 |
xml_util.set_value(doc, node, id_) |
133 | 149 |
else: last_only = False |
134 |
set_id(target, id_)
|
|
135 |
return get(doc, target, create, last_only)
|
|
150 |
set_id(path, id_)
|
|
151 |
return get(doc, path, create, last_only)
|
|
136 | 152 |
|
137 | 153 |
parent = node |
138 | 154 |
elem_idx += 1 |
Also available in: Unified diff
In data2xml, added shortcut for lookahead assertion using ! symbol