Project

General

Profile

« Previous | Next » 

Revision 25

In data2xml, added shortcut for lookahead assertion using ! symbol

View differences:

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