Source code for opyenxes.extension.std.XAbstractNestedAttributeSupport
from abc import abstractclassmethod
from opyenxes.factory.XFactoryRegistry import XFactoryRegistry
from opyenxes.model.XAttribute import XAttribute
[docs]class XAbstractNestedAttributeSupport:
"""This class offers generic support for extracting and assigning values to
and from nested attributes.
"""
[docs] @abstractclassmethod
def assign_value(self, element, value):
"""Abstract method to assign a value to an element.
:param element: The element to assign the value to.
:type element: XAttribute
:param value: The value to be assigned.
:type value: Any
"""
pass
[docs] @abstractclassmethod
def extract_value(self, element):
""" Abstract method to extract a value from an element.
:param element: The element to extract the value from.
:type element: `XAttribute`
"""
pass
[docs] def extract_values(self, element):
"""Retrieves a map containing all values for all child attributes of an
element. For example, the XES fragment: ::
<trace>
<string key="key.1" value="">
<float key="ext:attr" value="val.1"/>
<string key="key.1.1" value="">
<float key="ext:attr" value="val.1.1"/>
</string>
<string key="key.1.2" value="">
<float key="ext:attr" value="val.1.2"/>
</string>
</string>
<string key="key.2" value="">
<float key="ext:attr" value="val.2"/>
</string>
<string key="key.3" value="">
<float key="ext:attr" value="val.3"/>
</string>
</trace>
should result into the following:::
{"key.1": val.1, "key.2": val.2, "key.3": val.3}
:param element: Element to retrieve all values for.
:type element: `XAttributable`
:return: Dictionary with all child keys to values.
:rtype: dict(str: any}
"""
values = dict()
nested_values = self.extract_nested_values(element)
for keys in nested_values.keys():
if len(keys) == 1:
values[keys[0]] = nested_values[keys]
return values
[docs] def extract_nested_values(self, element):
"""Retrieves a map containing all values for all descending attributes
of an element. For example, the XES fragment:::
<trace>
<string key="key.1" value="">
<float key="ext:attr" value="val.1"/>
<string key="key.1.1" value="">
<float key="ext:attr" value="val.1.1"/>
</string>
<string key="key.1.2" value="">
<float key="ext:attr" value="val.1.2"/>
</string>
</string>
<string key="key.2" value="">
<float key="ext:attr" value="val.2"/>
</string>
<string key="key.3" value="">
<float key="ext:attr" value="val.3"/>
</string>
</trace>
should result into the following:::
{["key.1"]: val.1, ["key.1", "key.1.1"]: val.1.1, ["key.1", "key.1.2"]: val.1.2, ["key.2"]: val.2, ["key.3"]: val.3}
:param element: Element to retrieve all values for.
:type element: `XAttributable`
:return: Dictionary with all descending keys to values.
:rtype: dict(list[str]: Any)
"""
nested_values = dict()
for attr in element.get_attributes().values():
keys = list()
keys.append(attr.get_key())
self.__extract_nested_values_private__(attr, nested_values, keys)
return nested_values
def __extract_nested_values_private__(self, element, nested_values, keys):
""" helper and private method to assign the nested values.
"""
value = self.extract_value(element)
if value:
nested_values[keys] = value
for attr in element.get_attributes().values():
new_keys = list(keys)
new_keys.append(element.get_key())
self.__extract_nested_values_private__(attr, nested_values, new_keys)
[docs] def assign_values(self, element, values):
"""Assigns (to the given element) multiple values given their keys. Note
that as a side effect this method creates attributes when it does not
find an attribute with the proper key. For example, the call:::
assign_values(event, {"key.1": val.1, "key.2": val.2, "key.3": val.3})
should result into the following XES fragment:::
<event>
<string key="key.1" value="">
<float key="ext:attr" value="val.1"/>
</string>
<string key="key.2" value="">
<float key="ext:attr" value="val.2"/>
</string>
<string key="key.3" value="">
<float key="ext:attr" value="val.3"/>
</string>
</event>
:param element: Element to assign the values to.
:type element: `XAttributable`
:param values: dictionary with keys to values which are to be assigned.
:type values: dict(str: Any)
"""
nested_values = dict()
for key in values.keys():
keys = list()
keys.append(key)
nested_values[keys] = values[key]
self.assign_nested_values(element, nested_values)
[docs] def assign_nested_values(self, element, amounts):
"""Assigns (to the given event) multiple values given their key lists.
The i-th element in the key list should correspond to an i-level
attribute with the prescribed key. Note that as a side effect this
method creates attributes when it does not find an attribute with the
proper key. For example, the call:::
assignNestedValues(event, {["key.1"]: val.1, ["key.1", "key.1.1"]: val.1.1, ["key.1", "key.1.2"]: val.1.2, ["key.2"]: val.2, ["key.3"]: val.3})
should result into the following XES fragment:::
<event>
<string key="key.1" value="">
<float key="ext:attr" value="val.1"/>
<string key="key.1.1" value="">
<float key="ext:attr" value="val.1.1"/>
</string>
<string key="key.1.2" value="">
<float key="ext:attr" value="val.1.2"/>
</string>
</string>
<string key="key.2" value="">
<float key="ext:attr" value="val.2"/>
</string>
<string key="key.3" value="">
<float key="ext:attr" value="val.3"/>
</string>
</event>
:param element: Element to assign the values to.
:type element: `XAttributable`
:param amounts: Dictionary with key lists to values which are to be
assigned.
:type amounts: dict(list[str]: Any)
"""
for keys in amounts.keys():
self.__assign_nested_values_private__(element, keys, amounts[keys])
def __assign_nested_values_private__(self, element, keys, value):
""" helper and private method to assign the nested values.
"""
if len(keys) == 0:
if isinstance(element, XAttribute):
self.assign_value(element, value)
else:
key = keys[0]
keys_tail = keys[1:]
if key in element.get_attributes():
attr = element.get_attributes()[key]
else:
attr = XFactoryRegistry().current_default().create_attribute_literal(key, "", None)
element.get_attributes()[key] = attr
self.__assign_nested_values_private__(attr, keys_tail, value)