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

'''
    PM4Py – A Process Mining Library for Python
Copyright (C) 2024 Process Intelligence Solutions UG (haftungsbeschränkt)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or any later version.

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see this software project's root or
visit <https://www.gnu.org/licenses/>.

Website: https://processintelligence.solutions
Contact: info@processintelligence.solutions
'''
from lxml import etree, objectify

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, exec_utils
from enum import Enum


[docs] class Parameters(Enum): ENCODING = "encoding"
[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 = {} encoding = exec_utils.get_param_value(Parameters.ENCODING, parameters, None) parser = etree.XMLParser(remove_comments=True, encoding=encoding) F = open(path, "rb") xml_tree = objectify.parse(F, parser=parser) F.close() 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 = {} encoding = exec_utils.get_param_value(Parameters.ENCODING, parameters, constants.DEFAULT_ENCODING) if type(tree_string) is str: tree_string = tree_string.encode(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