Beispiel #1
0
    def delete_or_update_node(self, node, new_node):
        '''
        Delete or update a node from the XML DOM. If the node was shadowing an inherited node, the inherited
        node is (re-)inserted into the DOM (after merging with new_node in the case of an update) and returned.
        Calling delete_or_update_node on an inherited node has no effect.
        @node (Element) node to remove
        @new_node (Element) node to insert instead of the removed element; None to remove only 
        @return the (re-inserted) node (Element) or None
        '''

        # The three cases of deleting/updating a node:
        # The node is local (simplest case -- just remove it)
        #   - if updating, simply add the new node
        # The node is inherited (no, wait, this is the simplest case -- do nothing)
        # The node is shadowing an inherited node (remove the node)
        #   - if removing, reinsert the inherited node
        #   - if updating, merge the new node with the inherited node and insert

        # helper function to clean out all child nodes from shadowing_nodes
        def clean_shadownodes(node):
            for child_node in node:
                clean_shadownodes(child_node)
            if node in self._shadowing_nodes:
                del self._shadowing_nodes[node]
            assert node not in self._shadowing_nodes

        parent = node.getparent()
        node_index = parent.index(node)
        inherited_node = None
        reinserted_node = new_node
        if node in self._shadowing_nodes:
            inherited_node = copy.deepcopy(self._shadowing_nodes[node])
            if new_node is None:
                reinserted_node = inherited_node
                inherited_node = None
        elif node.get('inherited'):
            return
        else:
            pass

        clean_shadownodes(node)
        node_id = node_identity_string(node)
        parent.remove(node)

        if inherited_node is not None:
            assert new_node is not None
            XMLConfiguration._merge_nodes(inherited_node, new_node)
        if new_node is not None:
            self._add_shadowing_nodes(new_node, node_id)
        if reinserted_node is not None:
            parent.insert(node_index, reinserted_node)
        return reinserted_node
    def delete_or_update_node(self, node, new_node):
        '''
        Delete or update a node from the XML DOM. If the node was shadowing an inherited node, the inherited
        node is (re-)inserted into the DOM (after merging with new_node in the case of an update) and returned.
        Calling delete_or_update_node on an inherited node has no effect.
        @node (Element) node to remove
        @new_node (Element) node to insert instead of the removed element; None to remove only 
        @return the (re-inserted) node (Element) or None
        '''
        # The three cases of deleting/updating a node:
        # The node is local (simplest case -- just remove it)
        #   - if updating, simply add the new node
        # The node is inherited (no, wait, this is the simplest case -- do nothing)
        # The node is shadowing an inherited node (remove the node)
        #   - if removing, reinsert the inherited node
        #   - if updating, merge the new node with the inherited node and insert

        # helper function to clean out all child nodes from shadowing_nodes
        def clean_shadownodes(node):
            for child_node in node:
                clean_shadownodes(child_node)
            if node in self._shadowing_nodes:
                del self._shadowing_nodes[node]
            assert node not in self._shadowing_nodes
            
        parent = node.getparent()
        node_index = parent.index(node)
        inherited_node = None
        reinserted_node = new_node
        if node in self._shadowing_nodes:
            inherited_node = copy.deepcopy(self._shadowing_nodes[node])
            if new_node is None:
                reinserted_node = inherited_node
                inherited_node = None
        elif node.get('inherited'):
            return
        else:
            pass
            
        clean_shadownodes(node)
        node_id = node_identity_string(node)
        parent.remove(node)
        
        if inherited_node is not None:
            assert new_node is not None
            XMLConfiguration._merge_nodes(inherited_node, new_node)
        if new_node is not None:
            self._add_shadowing_nodes(new_node, node_id)
        if reinserted_node is not None:
            parent.insert(node_index, reinserted_node)
        return reinserted_node
Beispiel #3
0
    def copy_to_parent(self, node):
        '''
        Copies a local node to the parent configuration without deleting it. 
        @node (Element) to copy to parent
        '''

        # Helper routines:

        # Never copy description and parent nodes to parent
        def delete_immutable():
            id_strings = self.IMMUTABLE_NODE_IDS
            for id_string in id_strings:
                for n in self.find_all_by_id_string(id_string, clone):
                    n.getparent().remove(n)

        # Find deepest parent node of to-be-inserted node that is also in the parent config
        def get_insert_node(merge_node, nodes):
            nodes.append(merge_node)
            ins_node = self.find_by_id_string(node_identity_string(merge_node),
                                              parent_root)
            if ins_node is not None:
                return ins_node
            merge_node = merge_node.getparent()
            return get_insert_node(merge_node, nodes)

        # Remove all children for all nodes in the nodes list
        def strip_children(nodes):
            for n in nodes[:-1]:
                for subelement in n.getparent().getchildren():
                    if subelement is not n:
                        n.getparent().remove(subelement)

        # Remove "inherited" attribute from all nodes below tree_node that were
        # introduced by the immediate parent.  Remove all inherited nodes
        # that were introduced by a grandparent -- copying them to the parent
        # leads to incorrect results.
        def clear_inherited_attribute_or_delete_inherited_nodes(tree_node):
            nodes_to_delete = []
            for node in tree_node.iterchildren():
                if node.get('inherited') is not None:
                    if node.get('inherited') == parent_name:
                        del node.attrib['inherited']
                        clear_inherited_attribute_or_delete_inherited_nodes(
                            node)
                    else:
                        nodes_to_delete.append(node)
                else:
                    clear_inherited_attribute_or_delete_inherited_nodes(node)

            for node in nodes_to_delete:
                tree_node.remove(node)

        #work on clone_node
        id_string = node_identity_string(node)
        clone = copy.deepcopy(self.root_node())
        node = self.find_by_id_string(id_string, clone)

        #get parent project
        parent_file = self.get_last_writable_parent_file()
        parent_project = OpusProject()
        parent_project.open(parent_file)
        parent_name = parent_project.xml_config.name
        parent_root = parent_project.xml_config.tree.getroot()

        delete_immutable()

        parents_to_insert = []
        if node is not clone:
            insert_node = get_insert_node(node, parents_to_insert)

        node = parents_to_insert[-1]
        strip_children(parents_to_insert)
        clear_inherited_attribute_or_delete_inherited_nodes(node)

        XMLConfiguration._merge_nodes(insert_node, node)

        insert_parent = insert_node.getparent()
        insert_parent.replace(insert_node, node)

        # using parent_project.save() adds unnecessary attributes for some reason.
        parent_project.xml_config.save_as(parent_file)
    def copy_to_parent(self, node):
        '''
        Copies a local node to the parent configuration without deleting it. 
        @node (Element) to copy to parent
        '''
        # Helper routines:
        
        # Never copy description and parent nodes to parent
        def delete_immutable():
            id_strings = self.IMMUTABLE_NODE_IDS
            for id_string in id_strings:
                for n in self.find_all_by_id_string(id_string, clone):
                    n.getparent().remove(n)
    
        # Find deepest parent node of to-be-inserted node that is also in the parent config
        def get_insert_node(merge_node, nodes):
            nodes.append(merge_node)
            ins_node = self.find_by_id_string(node_identity_string(merge_node), parent_root) 
            if ins_node is not None:
                return ins_node
            merge_node = merge_node.getparent()
            return get_insert_node(merge_node, nodes)

        # Remove all children for all nodes in the nodes list
        def strip_children(nodes):
            for n in nodes[:-1]:
                for subelement in n.getparent().getchildren():
                    if subelement is not n:
                        n.getparent().remove(subelement)
        
        # Remove "inherited" attribute from all nodes below tree_node that were
        # introduced by the immediate parent.  Remove all inherited nodes
        # that were introduced by a grandparent -- copying them to the parent
        # leads to incorrect results.
        def clear_inherited_attribute_or_delete_inherited_nodes(tree_node):
            nodes_to_delete = []
            for node in tree_node.iterchildren():
                if node.get('inherited') is not None:
                    if node.get('inherited') == parent_name:
                        del node.attrib['inherited']
                        clear_inherited_attribute_or_delete_inherited_nodes(node)
                    else:
                        nodes_to_delete.append(node)
                else:
                    clear_inherited_attribute_or_delete_inherited_nodes(node)
            
            for node in nodes_to_delete:
                tree_node.remove(node)


        #work on clone_node
        id_string = node_identity_string(node)
        clone = copy.deepcopy(self.root_node())
        node = self.find_by_id_string(id_string, clone)
        
        #get parent project   
        parent_file = self.get_last_writable_parent_file()
        parent_project = OpusProject()
        parent_project.open(parent_file)
        parent_name = parent_project.xml_config.name
        parent_root = parent_project.xml_config.tree.getroot()
        
        delete_immutable()
  
        parents_to_insert = []
        if node is not clone:
            insert_node = get_insert_node(node, parents_to_insert)

        node = parents_to_insert[-1]
        strip_children(parents_to_insert)
        clear_inherited_attribute_or_delete_inherited_nodes(node)
        
        XMLConfiguration._merge_nodes(insert_node, node)
        
        insert_parent = insert_node.getparent()
        insert_parent.replace(insert_node, node)

        # using parent_project.save() adds unnecessary attributes for some reason.
        parent_project.xml_config.save_as(parent_file)