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 _before_insert_text(self, parent, new_text, k): """ check if a text node that will be remove has two sibbling text nodes to avoid coalescing two text nodes """ if k > 1: if 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 k+1 if k < len(parent[N_CHILDS]): if parent[N_CHILDS][k][N_TYPE] == NT_TEXT: tag = self.FAKE_TAG[:] if k <= nb_attrs(parent): self.add_action(['append_first', f_xpath(parent), tag]) else: self.add_action(['insert-after', f_xpath(parent[N_CHILDS][k]), tag]) insert_node(parent, tag, k) return k
def _make_move(self, n1, n2, k): # avoid coalescing two text nodes act_node = self._before_delete_node(n1) if act_node is not None and act_node[0] is n2 and act_node[1] < k: k += 1 if n1[N_TYPE] == NT_TEXT: k = self._before_insert_text(n2, n1, k) # avoid moving an attribute node on elif n1[N_TYPE] == NT_ATTN: ## n2[N_NAME] = 'A@LogilabXmldiffTmpAttr:%s'%n2[N_NAME][2:] ## n2[N_NAME] = '@LogilabXmldiffTmpAttr_%s'%n2[N_NAME] ## n2[N_VALUE] = 'LogilabXmldiffTmpAttr_%s'%n2[N_VALUE] ## self.add_action(['move-and-rename_node', n1, n2]) ## self.add_action(['rename_node', f_xpath(n2), n2[N_NAME][23:]]) # avoid moving attribute node from a place to another on the same node if not n1[N_PARENT] is n2: self.add_action(['move', n1, n2]) elif k <= nb_attrs(n2): self.add_action(['move-first', n1, n2]) else: self.add_action(['move-after', n1, n2[N_CHILDS][k-1]]) # real move delete_node(n1) insert_node(n2, n1, k)
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)