Exemple #1
0
    def test_move_node(self):
        # Move 1 down
        action = actions.MoveNode("/document/node[1]", "/document", 1)
        expected = "[move, /document/node[1], /document, 1]"
        self._format_test(action, expected)

        # Move 2 up (same result, different diff)
        action = actions.MoveNode("/document/node[2]", "/document", 0)
        expected = "[move, /document/node[2], /document, 0]"

        self._format_test(action, expected)
Exemple #2
0
    def test_move_node(self):
        # Move 1 down
        action = actions.MoveNode('/document/node[1]', '/document', 1)
        expected = '[move, /document/node[1], /document, 1]'
        self._format_test(action, expected)

        # Move 2 up (same result, different diff)
        action = actions.MoveNode('/document/node[2]', '/document', 0)
        expected = '[move, /document/node[2], /document, 0]'

        self._format_test(action, expected)
Exemple #3
0
    def test_move_node(self):
        # Move 1 down
        left = '<document><node id="1" /><node id="2" /></document>'
        action = actions.MoveNode("/document/node[1]", "/document", 1)
        expected = (START + ' id="1" diff:delete=""/><node id="2"/><node '
                    'id="1" diff:insert=""/></document>')

        self._format_test(left, action, expected)

        # Move 2 up (same result, different diff)
        left = '<document><node id="1" /><node id="2" /></document>'
        action = actions.MoveNode("/document/node[2]", "/document", 0)
        expected = (START + ' id="2" diff:insert=""/><node id="1"/><node '
                    'id="2" diff:delete=""/></document>')

        self._format_test(left, action, expected)
Exemple #4
0
    def test_move_node(self):
        # Move 1 down
        left = u'<document><node id="1" /><node id="2" /></document>'
        action = actions.MoveNode('/document/node[1]', '/document', 1)
        expected = START + u' id="1" diff:delete=""/><node id="2"/><node '\
            u'id="1" diff:insert=""/></document>'

        self._format_test(left, action, expected)

        # Move 2 up (same result, different diff)
        left = u'<document><node id="1" /><node id="2" /></document>'
        action = actions.MoveNode('/document/node[2]', '/document', 0)
        expected = START + u' id="2" diff:insert=""/><node id="1"/><node '\
            u'id="2" diff:delete=""/></document>'

        self._format_test(left, action, expected)
Exemple #5
0
    def test_rename_node(self):
        # Move 1 down
        action = actions.RenameNode("/document/node[1]", "newtag")
        expected = "[rename, /document/node[1], newtag]"
        self._format_test(action, expected)

        # Move 2 up (same result, different diff)
        action = actions.MoveNode("/document/node[2]", "/document", 0)
        expected = "[move-first, /document/node[2], /document]"
        self._format_test(action, expected)
Exemple #6
0
    def test_rename_node(self):
        # Move 1 down
        action = actions.RenameNode('/document/node[1]', 'newtag')
        expected = '[rename, /document/node[1], newtag]'
        self._format_test(action, expected)

        # Move 2 up (same result, different diff)
        action = actions.MoveNode('/document/node[2]', '/document', 0)
        expected = '[move-first, /document/node[2], /document]'
        self._format_test(action, expected)
Exemple #7
0
    def align_children(self, left, right):
        lchildren = [
            c for c in left.getchildren()
            if (id(c) in self._l2rmap
                and self._l2rmap[id(c)].getparent() is right)
        ]
        rchildren = [
            c for c in right.getchildren() if
            (id(c) in self._r2lmap and self._r2lmap[id(c)].getparent() is left)
        ]
        if not lchildren or not rchildren:
            # Nothing to align
            return

        lcs = utils.longest_common_subsequence(
            lchildren, rchildren, lambda x, y: self._l2rmap[id(x)] is y)

        for x, y in lcs:
            # Mark these as in order
            self._inorder.add(lchildren[x])
            self._inorder.add(rchildren[y])

        # Go over those children that are not in order:
        for lchild in lchildren:
            if lchild in self._inorder:
                # Already aligned
                continue

            rchild = self._l2rmap[id(lchild)]
            right_pos = self.find_pos(rchild)
            rtarget = rchild.getparent()
            ltarget = self._r2lmap[id(rtarget)]
            yield actions.MoveNode(utils.getpath(lchild),
                                   utils.getpath(ltarget), right_pos)
            # Do the actual move:
            left.remove(lchild)
            ltarget.insert(right_pos, lchild)
            # Mark the nodes as in order
            self._inorder.add(lchild)
            self._inorder.add(rchild)
Exemple #8
0
    def diff(self, left=None, right=None):
        # Make sure the matching is done first, diff() needs the l2r/r2l maps.
        if not self._matches:
            self.match(left, right)

        # The paper talks about the five phases, and then does four of them
        # in one phase, in a different order that described. This
        # implementation in turn differs in order yet again.
        ltree = self.left.getroottree()

        for rnode in utils.breadth_first_traverse(self.right):
            # (a)
            rparent = rnode.getparent()
            ltarget = self._r2lmap.get(id(rparent))

            # (b) Insert
            if id(rnode) not in self._r2lmap:
                # (i)
                pos = self.find_pos(rnode)
                # (ii)
                if rnode.tag is etree.Comment:
                    yield actions.InsertComment(utils.getpath(ltarget, ltree),
                                                pos, rnode.text)
                    lnode = etree.Comment(rnode.text)
                else:
                    yield actions.InsertNode(utils.getpath(ltarget, ltree),
                                             rnode.tag, pos)
                    lnode = ltarget.makeelement(rnode.tag)

                    # (iii)
                self.append_match(lnode, rnode, 1.0)
                ltarget.insert(pos, lnode)
                self._inorder.add(lnode)
                self._inorder.add(rnode)
                # And then we update attributes. This is different from the
                # paper, because the paper assumes nodes only has labels and
                # values. Nodes also has texts, we do them later.
                for action in self.update_node_attr(lnode, rnode):
                    yield action

            # (c)
            else:
                # Normally there is a check that rnode isn't a root,
                # but that's perhaps only because comparing valueless
                # roots is pointless, but in an elementtree we have no such
                # thing as a valueless root anyway.
                # (i)
                lnode = self._r2lmap[id(rnode)]

                # (iii) Move
                lparent = lnode.getparent()
                if ltarget is not lparent:
                    pos = self.find_pos(rnode)
                    yield actions.MoveNode(utils.getpath(lnode, ltree),
                                           utils.getpath(ltarget, ltree), pos)
                    # Move the node from current parent to target
                    lparent.remove(lnode)
                    ltarget.insert(pos, lnode)
                    self._inorder.add(lnode)
                    self._inorder.add(rnode)

                # Rename
                for action in self.update_node_tag(lnode, rnode):
                    yield action

                # (ii) Update
                # XXX If they are exactly equal, we can skip this,
                # maybe store match results in a cache?
                for action in self.update_node_attr(lnode, rnode):
                    yield action

            # (d) Align
            for action in self.align_children(lnode, rnode):
                yield action

            # And lastly, we update all node texts. We do this after
            # aligning children, because when you generate an XML diff
            # from this, that XML diff update generates more children,
            # confusing later inserts or deletes.
            lnode = self._r2lmap[id(rnode)]
            for action in self.update_node_text(lnode, rnode):
                yield action

        for lnode in utils.reverse_post_order_traverse(self.left):
            if id(lnode) not in self._l2rmap:
                # No match
                yield actions.DeleteNode(utils.getpath(lnode, ltree))
                lnode.getparent().remove(lnode)
Exemple #9
0
 def _handle_move(self, node, target, position):
     return actions.MoveNode(node, target, int(position))