Source code for pm4py.objects.process_tree.importer.variants.ptml

'''
    This file is part of PM4Py (More Info: https://pm4py.fit.fraunhofer.de).

    PM4Py is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    PM4Py is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PM4Py.  If not, see <https://www.gnu.org/licenses/>.
'''
import os
import tempfile

import deprecation
from lxml import etree, objectify

from pm4py.meta import VERSION
from pm4py.objects.process_tree.obj import ProcessTree
from pm4py.objects.process_tree.obj import Operator
from pm4py.objects.process_tree.utils.generic import tree_sort
from pm4py.util import constants


@deprecation.deprecated(deprecated_in="2.1.1", removed_in="3.0",
                        current_version=VERSION,
                        details="Use the entrypoint import_from_string method")
def import_tree_from_string(tree_string, parameters=None):
    """
    Import a process tree from an XML string

    Parameters
    ----------
    tree_string
        Process tree expressed as PNML string
    parameters
        Other parameters of the algorithm

    Returns
    ----------
    tree
        Process tree
    """
    if parameters is None:
        parameters = {}

    fp = tempfile.NamedTemporaryFile(suffix='.ptml')
    fp.close()

    if type(tree_string) is bytes:
        with open(fp.name, 'wb') as f:
            f.write(tree_string)
    else:
        with open(fp.name, 'w') as f:
            f.write(tree_string)

    tree = apply(fp.name, parameters=parameters)
    os.remove(fp.name)
    return tree


[docs]def apply(path, parameters=None): """ Imports a PTML file from the specified path Parameters --------------- path Path parameters Possible parameters Returns --------------- tree Process tree """ if parameters is None: parameters = {} parser = etree.XMLParser(remove_comments=True) xml_tree = objectify.parse(path, parser=parser) root = xml_tree.getroot() return import_tree_from_xml_object(root, parameters=parameters)
[docs]def import_tree_from_string(tree_string, parameters=None): """ Imports a PTML file from a (binary) string Parameters --------------- tree_string String representing the process tree parameters Possible parameters Returns --------------- tree Process tree """ if parameters is None: parameters = {} if type(tree_string) is str: tree_string = tree_string.encode(constants.DEFAULT_ENCODING) parser = etree.XMLParser(remove_comments=True) root = objectify.fromstring(tree_string, parser=parser) return import_tree_from_xml_object(root, parameters=parameters)
[docs]def import_tree_from_xml_object(root, parameters=None): """ Imports a process tree from the XML object Parameters --------------- root Root of the XML object parameters Possible parameters Returns --------------- tree Process tree """ if parameters is None: parameters = {} nodes = {} for c0 in root: root = c0.get("root") for child in c0: tag = child.tag id = child.get("id") name = child.get("name") sourceId = child.get("sourceId") targetId = child.get("targetId") if name is not None: # node if tag == "and": operator = Operator.PARALLEL label = None elif tag == "sequence": operator = Operator.SEQUENCE label = None elif tag == "xor": operator = Operator.XOR label = None elif tag == "xorLoop": operator = Operator.LOOP label = None elif tag == "or": operator = Operator.OR label = None elif tag == "manualTask": operator = None label = name elif tag == "automaticTask": operator = None label = None else: raise Exception("unknown tag: " + tag) tree = ProcessTree(operator=operator, label=label) nodes[id] = tree else: nodes[sourceId].children.append(nodes[targetId]) nodes[targetId].parent = nodes[sourceId] # make sure that .PTML files having loops with 3 children are imported # into the PM4Py process tree structure # we want loops to have two children for node in nodes.values(): if node.operator == Operator.LOOP and len(node.children) == 3: if not (node.children[2].operator is None and node.children[2].label is None): parent_node = node.parent new_parent_node = ProcessTree(operator=Operator.SEQUENCE, label=None) node.parent = new_parent_node new_parent_node.children.append(node) node.children[2].parent = new_parent_node new_parent_node.children.append(node.children[2]) if parent_node is not None: new_parent_node.parent = parent_node del parent_node.children[parent_node.children.index(node)] parent_node.children.append(new_parent_node) del node.children[2] root = nodes[root] tree_sort(root) return root