An-augmented-Tree-Item¶
There are 3 basic types of tree items derived from the abstract base class AnAugmentedTreeItem
. These 3 tree items represent values, sequences and mappings.
The following example shows nested data and the ‘augmented’ view on it. A tree item has always a primekey. Using schemas this primekey doesn’t necessarily need to be equal to the real index/key within the nested data. The primename is just an association for the tree item. The primevalue of the tree item referees to the nested data the tree item is attached to. So the primevalue of the root tree item always shows the complete nested data.
[1]:
from augmentedtree import AugmentedTree, PRIMARYVALUE_KEY
import json
nested_data = [{"a1": 1}, {"a2": 2, "a3": [3, 4, 5], }]
pretty_printed_data = json.dumps(nested_data, indent=" ")
print(pretty_printed_data)
[
{
"a1": 1
},
{
"a2": 2,
"a3": [
3,
4,
5
]
}
]
Above is a pretty print using json.dumps showing the how the nested data looks like.
The nested data within a 3 column view (primekey, primename) with primevalue (the data of AnAugmentedTreeItem) as an additional column.
[2]:
tree = AugmentedTree(nested_data)
tree.print(additional_columns=[PRIMARYVALUE_KEY])
Primevalue
[..] ' [{'a1': 1}, {'a2': 2, 'a3': [3, 4, 5]}]
0. ' {'a1': 1}
a1: 1 ' 1
1. ' {'a2': 2, 'a3': [3, 4, 5]}
a2: 2 ' 2
a3: [3, 4, 5] ' [3, 4, 5]
Value (& Sequence)¶
A value tree item is being considered any type not being a Mapping.
Sequences will be treated as a value if they do not possess a Mapping. A SequenceTreeItem will behave like a Sequence.
Mappings¶
The items of a Mapping can be divided into 2 groups. Values which should be shown and metadata which will be hidden. There are 2 possibilities to define this behavior.
Flat Mapping item
A flat mapping item has its values and metadata within the same level.
[3]:
from augmentedtree import MappingSchemaBuilder, AugmentedTree, use_mappingtree_schemas
flat_pizza = {
"type": "flat-pizza",
"name": "Salami",
"number": 62,
"tomato sauce": "1 scoop",
"cheese": "A lot",
"salami": "6 slices",
"allergens": [10, 17, 24]
}
schema = MappingSchemaBuilder.construct(
identifier=("type", "flat-pizza"),
primarykey="type",
primaryname="name",
additional_metafieldkeys=["allergens", "number"]
)
use_mappingtree_schemas(schema)
AugmentedTree(flat_pizza).print()
flat-pizza Salami
tomato sauce: 1 scoop
cheese: A lot
salami: 6 slices
Nested Mapping item
A nested mapping item has is values within a additional level. Metadata is at the root level of this item. This ‘rootlevel’ is skipped in the view.
[4]:
nested_pizza = {
"type": "nested-pizza",
"name": "Salami",
"number": 62,
"ingredients": {
"tomato sauce": "1 scoop",
"cheese": "A lot",
"salami": "6 slices",
},
"allergens": [10, 17, 24]
}
schema = MappingSchemaBuilder.construct(
identifier=("type", "nested-pizza"),
primarykey="type",
primaryname="name",
outervalues_key="ingredients"
)
use_mappingtree_schemas(schema)
AugmentedTree(nested_pizza).print()
nested-pizza Salami
tomato sauce: 1 scoop
cheese: A lot
salami: 6 slices
Schemas¶
Schemas are the essential tool to give mapping a more semantic like view. Any dictionary containing the right set of keys of MappingSchema can be used as a schema. IDENTIFIER of MappingSchema is mandatory. Either METAFIELDKEYS or OUTERVALUES are required additionally. OUTERVALUES always overrules METAFIELDKEYS.
All other entries are optional and do have impact on the representation within the view, which will be shown in the following examples, starting with the ‘flat-pizza’ from above.
Overriding default metafieldkey definition keeps the identifier visible.
[5]:
schema = MappingSchemaBuilder.construct(
identifier=("type", "flat-pizza"),
metafieldkeys=["number", "allergens"]
)
use_mappingtree_schemas(schema, override_existing=True)
AugmentedTree(flat_pizza).print()
{..}
type: flat-pizza
name: Salami
tomato sauce: 1 scoop
cheese: A lot
salami: 6 slices
Adding metafieldkeys to the defaults hides the identifier.
[6]:
schema = MappingSchemaBuilder.construct(
identifier=("type", "flat-pizza"),
additional_metafieldkeys=["number", "allergens"]
)
use_mappingtree_schemas(schema, override_existing=True)
AugmentedTree(flat_pizza).print()
{..}
name: Salami
tomato sauce: 1 scoop
cheese: A lot
salami: 6 slices
Supplied primarykey and primaryname are default metadatakeys hiding both items automatically.
[7]:
schema = MappingSchemaBuilder.construct(
identifier=("type", "flat-pizza"),
primarykey="type",
primaryname="name",
additional_metafieldkeys=["number", "allergens"]
)
use_mappingtree_schemas(schema, override_existing=True)
AugmentedTree(flat_pizza).print()
flat-pizza Salami
tomato sauce: 1 scoop
cheese: A lot
salami: 6 slices
Outervalues overrules metadatakeys. If an item of a mapping is defined to represent the real values (or children) of this collection, then automatically all root level items of this mapping are rendered to metadata.
[8]:
schema = MappingSchemaBuilder.construct(
identifier=("type", "nested-pizza"),
metafieldkeys=["these", "are", "now", "irrelevant"],
outervalues_key="ingredients"
)
use_mappingtree_schemas(schema, override_existing=True)
AugmentedTree(nested_pizza).print(additional_columns=["@name", "@allergens"])
@name @allergens
{..} ' Salami ' [10, 17, 24]
tomato sauce: 1 scoop ' Salami ' [10, 17, 24]
cheese: A lot ' Salami ' [10, 17, 24]
salami: 6 slices ' Salami ' [10, 17, 24]
Paths within the augmentation¶
AnAugmentedTreeItem has 2 paths. It’s real path is the location within the original nested datastructure the tree items are attached to. The tree item’s augmented path depicts the location within the augmentation changed by schemas.
[9]:
from dicthandling import read_from_json_file
# get nested data and schema for the example
nested_data = read_from_json_file("resources/nested_data_of_examples.json", "AATI/path_example")
tree_without = AugmentedTree(nested_data, use_schemas=False)
tree_without.print()
{..}
The story:
type: example
name: W.
key: Richard
items:
0.
type: example
name: steed
key: mighty
items:
0.
type: example
name: along
key: rides
items:
into: the sunset
From the data above the last item with the primekey into is selected, the item’s TreePath retrieved and both real path as well augmented path shown. Since no schemas were applied, both are identical.
[10]:
real_and_augmented_path_is_identical = tree_without.select("into")
items_treepath = real_and_augmented_path_is_identical.paths[0]
print(" real path:", items_treepath.real_path)
print("augmented path:", items_treepath.augmented_path)
real path: /The story/items/0/items/0/items/into
augmented path: /The story/items/0/items/0/items/into
Now the whole process will be repeated, but this time a schema is applied to the nested data, resulting in a different view off it. Both paths differs in this example, due to the schema.
The exemplary data can be found within a json-file.
[11]:
schema_kwargs = read_from_json_file("resources/nested_data_of_examples.json", "AATI/path_example-schema")
example_schema = MappingSchemaBuilder.construct(**schema_kwargs)
use_mappingtree_schemas(example_schema)
tree_with_schema = AugmentedTree(nested_data)
tree_with_schema.print()
augmented_path_differs_from_real = tree_with_schema.select("into")
items_treepath = augmented_path_differs_from_real.paths[0]
print(" real path:", items_treepath.real_path)
print("augmented path:", items_treepath.augmented_path)
{..}
Richard: W.
mighty: steed
rides: along
into: the sunset
real path: /The story/items/0/items/0/items/into
augmented path: /Richard/mighty/rides/into
[12]:
# Using the origin data and navigating through it
print(tree_with_schema["The story"]["items"][0]["items"][0]["items"]["into"])
# Using the augmented path
print(tree_with_schema["Richard/mighty/rides/into"])
the sunset
the sunset