def add_action(self, action): if len(action) > 2 and type(action[A_N2]) == types.ListType: if type(action[A_N1]) == types.ListType: #swap or move node action[A_N1] = f_xpath(action[A_N1]) action[A_N2] = f_xpath(action[A_N2]) AbstractFormatter.add_action(self, action)
def _fmes_step2(self, tree1, tree2): """ the delete_node phase of the edit script algorithm instead of the standard algorithm, walk on tree1 in pre order and add a remove action on node not marked as mapped. Avoiding recursion on these node allow to extract remove on subtree instead of leaf do not use next_sibling for performance issue """ stack = [] i = 0 node = tree1 while node is not None: if node[N_MAPPED] != TRUE: if node[N_PARENT] and len(node[N_PARENT][N_CHILDS]) > i+1: next_node = node[N_PARENT][N_CHILDS][i+1] # if next node is a text node to remove, switch actions if next_node[N_TYPE] == NT_TEXT and \ next_node[N_MAPPED] != TRUE: self.add_action(['remove', f_xpath(next_node)]) delete_node(next_node) try: next_node = node[N_PARENT][N_CHILDS][i+1] except: next_node = None else: next_node = None self.add_action(['remove', f_xpath(node)]) delete_node(node) node = next_node elif node[N_CHILDS]: # push next sibbling on the stack if node[N_PARENT] and len(node[N_PARENT][N_CHILDS]) > i+1 : stack.append((node[N_PARENT][N_CHILDS][i+1], i+1)) node = node[N_CHILDS][0] i = 0 elif node[N_PARENT] and len(node[N_PARENT][N_CHILDS]) > i+1: i += 1 node = node[N_PARENT][N_CHILDS][i] #next_sibling(node) else: node = None if node is None and stack: node, i = stack.pop()
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 _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 add_action(self, action): if action[A_DESC] == 'move-first': # replace move-first with remove and insert (sibling nodes) self.edit_s.append(['remove', f_xpath(action[A_N1])]) self.edit_s.append(['append', f_xpath(action[A_N2]), action[A_N1]]) elif action[A_DESC] == 'move-after': # replace move-after with remove and insert (sibling nodes) self.edit_s.append(['remove', f_xpath(action[A_N1])]) self.edit_s.append(['insert-after', f_xpath(action[A_N2]), action[A_N1]]) elif action[A_DESC] == 'move-and-rename': # replace move-and-rename with remove and insert (sibling nodes) self.edit_s.append(['remove', f_xpath(action[A_N1])]) self.edit_s.append(['insert-after', f_xpath(action[A_N2][N_PARENT]), action[A_N2]]) elif action[A_DESC] == 'swap': # replace swap with remove and insert (sibling nodes) self.edit_s.append(['remove', f_xpath(action[A_N2])]) self.edit_s.append(['insert-after', f_xpath(action[A_N1]), action[A_N2]]) else: self.edit_s.append(action)
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)