def _before_delete_node(self, node): """ check if a text node will be inserted with a sibbling text node to avoid coalescing two text nodes """ k = get_pos(node) parent = node[N_PARENT] if k >= 1 and k+1 < len(parent[N_CHILDS]): if parent[N_CHILDS][k-1][N_TYPE] == NT_TEXT and \ parent[N_CHILDS][k+1][N_TYPE] == NT_TEXT: tag = self.FAKE_TAG[:] self.add_action(['insert-after', f_xpath(parent[N_CHILDS][k-1]), tag]) insert_node(parent, tag, k) return parent, k return None
def _find_pos(self, x): """ find the position of a node in the destination tree (tree2) do not use previous_sibling for performance issue """ y = x[N_PARENT] # if x is the leftmost child of y in order, return 1 for v in y[N_CHILDS]: if v[N_INORDER]: if v is x: # return 0 instead of 1 here since the first element of a # list have index 0 return 0 break # looking for rightmost left sibling of y INORDER i = get_pos(x) - 1 while i >= 0: v = y[N_CHILDS][i] if v[N_INORDER]: break i -= 1 u = partner(1, v) if not u is None: return get_pos(u)+1
def _fmes_step1(self, tree2, tree1): """ first step of the edit script algorithm combines the update, insert, align and move phases """ mapping = self._mapping fp = self._find_pos al = self._align_children _partner = partner # x the current node in the breadth-first order traversal for x in make_bfo_list(tree2): y = x[N_PARENT] z = _partner(1, y) w = _partner(1, x) # insert if not w: todo = 1 # avoid to add existing attribute node if x[N_TYPE] == NT_ATTN: for n in z[N_CHILDS]: if n[N_TYPE] != NT_ATTN: break elif n[N_VALUE] == x[N_VALUE]: # FIXME: n should yet be mapped todo = None w = n w[N_MAPPED] = TRUE mapping.append((w, x)) delete_node(w[N_CHILDS][0]) break if todo is not None: x[N_INORDER] = TRUE k = fp(x) # w = copy(x) w = x[:] w[N_CHILDS] = [] w.append(TRUE) # <-> w[N_MAPPED] = TRUE mapping.append((w, x)) # avoid coalescing two text nodes if w[N_TYPE] == NT_TEXT: k = self._before_insert_text(z, w, k) # real insert on tree 1 insert_node(z, w, k) # make actions on subtree self._dict[id(w)] = ww = w[:] ww[N_CHILDS] = [] # preformat action if not self._dict.has_key(id(z)): if w[N_TYPE] == NT_ATTV: action = ['update', f_xpath(z), w[N_VALUE]] elif w[N_TYPE] == NT_ATTN: action = ['append', f_xpath(z), ww] elif z[N_TYPE] == NT_ROOT: action = ['append-first', '/', ww] else: if ww[N_VALUE] == "spoken-languages": self.test = ww k = get_pos(w) if k <= nb_attrs(z): action = ['append-first', f_xpath(z), ww] else: action = ['insert-after', f_xpath(z[N_CHILDS][k-1]), ww] self.add_action(action) else: insert_node(self._dict[id(z)], ww, k) elif x[N_NAME] != '/': v = w[N_PARENT] # update if w[N_VALUE] != x[N_VALUE]: # format action if w[N_TYPE] in (NT_NODE, NT_ATTN): self.add_action(['rename', f_xpath(w), x[N_VALUE]]) else: self.add_action(['update', f_xpath(w), x[N_VALUE]]) # real update on t1 w[N_VALUE] = x[N_VALUE] # this is necessary for xpath rename_node(w, x[N_NAME]) # move x if parents not mapped together if not has_couple(v, y): x[N_INORDER] = TRUE k = fp(x) self._make_move(w, z, k) # align children al(w, x)