From 96e5eb765e42d71bf06f8a33c825fc235b4f6699 Mon Sep 17 00:00:00 2001 From: Daniel <d.hornung@indiscale.com> Date: Tue, 27 Feb 2024 09:38:58 +0100 Subject: [PATCH] DOC: More specs --- src/doc/table-json-conversion/specs.md | 220 +++++++++++------- .../{how_to_schema => how_to_schema.md} | 0 2 files changed, 139 insertions(+), 81 deletions(-) rename unittests/table_json_conversion/{how_to_schema => how_to_schema.md} (100%) diff --git a/src/doc/table-json-conversion/specs.md b/src/doc/table-json-conversion/specs.md index 3768ba1e..2a9b37b9 100644 --- a/src/doc/table-json-conversion/specs.md +++ b/src/doc/table-json-conversion/specs.md @@ -1,3 +1,5 @@ +# Konversion zwischen LinkAhead-Datenmodellen, JSON-Schema und XLSX (und zurück) # + Top level of json must be a dict. keys of the dict are RT names. @@ -6,12 +8,14 @@ Frage: is the first RT never an array? Do not use sheet name, but only content of hidden rows +## Datenmodelle in JSON-Schema und JSON-Daten ## +Das Datenmodell in LinkAhead legt fest, welche Arten von Records es in einer LinkAhead-Instanz gibt +und wie diese aussehen. Dieses Datenmodell kann auch in einem JSON Schema repräsentiert werden, dass +die Struktur von JSON Dateien festlegt, die zu dem Datenmodell gehörige Records enthält. -Das Datenmodell in LinkAhead legt fest, welche Arten von Records es in einer LinkAhead-Instanz -gibt und wie diese aussehen. Diese Datenmodell kann auch in einem JSON Schema repräsentiert werden, -dass die Struktur von JSON Dateien festlegt, die zu dem Datenmodell gehörige Records enthält. Zum Beispiel kann das folgende JSON den Record einer Person beschreiben: + ```JSON { "Person": { @@ -21,36 +25,48 @@ Zum Beispiel kann das folgende JSON den Record einer Person beschreiben: } ``` -Das JSON Schema schreibt eine konkrete Struktur vor und kann zugehörige JSON Dateien können genutzt werden -um Daten zu bestimmten Record Strukturen zu repräsentieren. Beispielsweise könnte man ein JSON Schema erstellen, -dass es erlaubt "Training" Records mit Informationen zu abgehaltenen Trainings speichern. Dies ist insbesondere wertvoll -beim Datenim- und export. Man könnte basierend auf dem im Folgenden beschriebenen Webformulare basieren -oder es nutzen um in LinkAhead gespeicherte Objekte als JSON zu exportieren. - -Im Folgenden wird beschrieben, wie JSON Dateien mit solchen Records in XLSX Dateien umgewandelt -werden, bzw. wie aus XLSX-Dateien JSON Dateien mit Records erstellt werden. - -Der Attributname (oben "Person") legt den RecordType fest und der Wert diese Attributs kann -entweder ein Objekt oder eine Liste sein. Ist es ein Objekt (wie im obigen Beispiel), so wird ein -einzelner Record repräsentiert. Bei einer Liste mehrere Records, die den gleichen RecordType als -Parent haben. -Die Properties des Records (oben "family_name" und "given_name") werden zu Spalten im XLSX. -Die Properties haben wiederum einen Attributnamen und einen Wert. Der Wert kann -a. primitiv (Text, Zahl, Boolean, ...) -b. ein Record -c. eine Liste von primitiven Typen +Ein *JSON Schema* schreibt eine konkrete Struktur vor, und die zugehörige JSON Dateien können +genutzt werden, um Daten zu bestimmten Record-Strukturen zu repräsentieren. Beispielsweise könnte +man ein JSON Schema erstellen, dass es erlaubt "Training" Records mit Informationen zu abgehaltenen +Trainings zu speichern. Dies ist insbesondere wertvoll beim Datenim- und export. Man +könnte Webformulare aus dem Json Schema generieren oder es nutzen, um in LinkAhead gespeicherte +Objekte als JSON zu exportieren. + +## Von JSON zu XLSX: Datenrepräsentation ## + +Im Folgenden wird beschrieben, wie JSON Dateien, die LinkAhead-Records reprästentieren in XLSX +Dateien umgewandelt werden, bzw. wie aus XLSX-Dateien JSON Dateien mit Records erstellt werden. + +Der Attributname (oben "Person") legt den RecordType fest und der Wert diese Attributs kann entweder +ein Objekt oder eine Liste sein. Ist es ein Objekt (wie im obigen Beispiel), so wird ein einzelner +Record repräsentiert. Bei einer Liste mehrere Records, die den gleichen RecordType als Parent +haben. + +Die *Properties* des Records (oben `family_name` und `given_name`) werden zu *Spalten* im XLSX. Die +Properties haben wiederum einen Attributnamen und einen Wert. Der Wert kann + +a. primitiv (Text, Zahl, Boolean, ...) +b. ein Record +c. eine Liste von primitiven Typen d. eine Liste von Records + sein. -In den Fällen a. und c. wird in XLSX eine Zelle in der zur Property gehörigen Spalte erstellt. Im Fall b. -wird prinzipiell für die Properties des Records Spalten erstellt. Tatsächlich wird der referenzierte Record genauso behandelt wie -der ursprüngliche. D.h. die Fälle a.-d. werden wieder für die einzelnen Properties betrachtet. -Für den Fall d. ist die zweidimensionale Struktur eines XLSX Blatts nicht ausreichend. Daher werden für solche Fälle neue XLSX Blätter erstellt. -In diesen werden die referenzierten Records behandelt wie oben beschrieben. Es gibt jedoch zusätzliche Spalten die es erlauben zu erkennen von -welchem Record die Records referenziert werden. +In den Fällen *a.* und *c.* wird in XLSX eine Zelle in der zur Property gehörigen Spalte erstellt. +Im Fall *b.* wird prinzipiell für die Properties des Records Spalten erstellt. Tatsächlich wird der +referenzierte Record genauso behandelt wie der ursprüngliche. D.h. die Fälle a.-d. werden wieder +für die einzelnen Properties betrachtet. + +Für den Fall *d.* ist die zweidimensionale Struktur eines XLSX Blatts nicht ausreichend. Daher +werden für solche Fälle *neue* XLSX-Blätter/-Tabellen erstellt. + +In diesen werden die referenzierten Records behandelt wie oben beschrieben. Es gibt jedoch +zusätzliche Spalten die es erlauben zu erkennen, von welchem "externen" Record diese Records +referenziert werden. Wir betrachten diese vier Fälle nun im Detail: -a. Properties mit primitiven Datentypen + +### a. Properties mit primitiven Datentypen ### ```JSON { @@ -63,38 +79,36 @@ a. Properties mit primitiven Datentypen } } ``` -Dies würde in einem XLSX Blatt mit dem folgenden Inhalt abgebildet: - -| date | url | duration | participants | remote | -|------|-----|-------------------|-----|---|----| -| 2023-01-01 | www.indiscale.com | 1.0 | 1 | false | +Dieser Eintrag wird in einem XLSX-Blatt mit dem folgenden Inhalt abgebildet: -b. Property, die einen Record referenziert +| date | url | duration | participants | remote | +|------------|-------------------|----------|--------------|--------| +| 2023-01-01 | www.indiscale.com | 1.0 | 1 | false | +### b. Property, die einen Record referenziert ### ```JSON { "Training": { "date": "2023-01-01", "supervisor": { - "family_name": "Steve", + "family_name": "Stevenson", "given_name": "Stevie", } } } ``` -Dies würde in einem XLSX Blatt mit dem folgenden Inhalt abgebildet: +Dieser Eintrag wird in einem XLSX Blatt mit dem folgenden Inhalt abgebildet: -| date | supervisor.family_name | supervisor.given_name | -|------|-----|-------------------| -| 2023-01-01 | Steve | Stevie | +| date | `supervisor.family_name` | `supervisor.given_name` | +|------------|--------------------------|-------------------------| +| 2023-01-01 | Stevenson | Stevie | -Beachten Sie, dass die Spaltennamen umbenannt werden dürfen. Die Zuordnung der Spalte zu Properties von -Records wird über den Inhalt von versteckten Zeilen gewährleistet. - -c. Properties, die Listen mit Werten von primitiven Datentypen enthalten +Beachten Sie, dass die Spaltennamen umbenannt werden dürfen. Die Zuordnung der Spalte zu Properties +von Records wird über den Inhalt von versteckten Zeilen gewährleistet. +### c. Properties, die Listen mit Werten von primitiven Datentypen enthalten ### ```JSON { @@ -105,19 +119,16 @@ c. Properties, die Listen mit Werten von primitiven Datentypen enthalten } ``` -Dies würde in einem XLSX Blatt mit dem folgenden Inhalt abgebildet: - -| url | subjects | -|------|-----|-------------------|-----|---|----| -| www.indiscale.com | Math;Physics | - +Dieser Eintrag würde in einem XLSX Blatt mit dem folgenden Inhalt abgebildet: -Die Listenelemente werden separiert von ``;`` in die Zelle geschrieben. -Wenn die Elemente den Separator ``;`` enthalten, dann wird dieser mit einem ``\`` escaped. +| url | subjects | +|-------------------|--------------| +| www.indiscale.com | Math;Physics | +Die Listenelemente werden separiert von ``;`` in die Zelle geschrieben. Wenn die Elemente den +Separator ``;`` enthalten, dann wird dieser mit einem ``\`` escaped. -d. Properities, die Listen mit Referenzen enthalten - +### d. Properties, die Listen mit Referenzen enthalten ### ```JSON { @@ -127,45 +138,92 @@ d. Properities, die Listen mit Referenzen enthalten { "family_name": "Sky", "given_name": "Max", - },{ + }, + { "family_name": "Sky", "given_name": "Min", - }], + } + ] } } ``` -Da die beiden Coaches nicht vernünftig in einer Zelle dargestellt werden können, bedarf es nun eines +Da die beiden Coaches nicht vernünftig in einer Zelle dargestellt werden können, bedarf es nun eines weiteren Tabellenblatts, das die Eigenschaften der Coaches enthält. -Das Blatt zu den Trainings enthält in diesem Beispiel nur die "date" Spalte: +Das Blatt zu den *Trainings* enthält in diesem Beispiel nur die "date" Spalte: -| date | -|------| +| date | +|------------| | 2023-01-01 | -Zusätzlich gibt es ein weiteres Blatt in dem die Coaches gespeichert werden. -Hier ist nun entscheidend, dass definiert wird, wie von potentiell mehreren "Trainings" das richtige Element gewählt wird. -In diesem Fall bedeutet dies, dass das "date" eindeutig sein muss -TODO: In welchem Scope gilt diese Eindeutigkeit? Können wir dies checken? -Das zweite Blatt sieht dann wie folgt aus - -| date | coach.family_name | coach.given_name | -|------|-|-| -| 2023-01-01 | Sky | Max| -| 2023-01-01 | Sky | Min| - +Zusätzlich gibt es ein *weiteres* Blatt in dem die Coaches gespeichert werden. Hier ist nun +entscheidend, dass definiert wird, wie von potentiell mehreren "Trainings" das richtige Element +gewählt wird. In diesem Fall bedeutet dies, dass das "date" eindeutig sein muss. +TODO: In welchem Scope gilt diese Eindeutigkeit? Können wir dies checken? -# Hidden automation logic - -The first column in each sheet will be hidden and it will contain an entry in each row that needs special -treatment. The following values are used: -``COL_TYPE``: typically the first row. It indicates the row that defines the type of columns (``FOREIGN`` or ``VALUE``). -``PATH``: indicates that the row is used to define the path within the JSON -``IGNROE``: row is ignored; It can be used for explanatory texts or layout +Das zweite Blatt sieht dann wie folgt aus -If we want to put the value of a given cell into the JSON, we traverse all path elements given in rows with the ``PATH`` value from row with lowest index to the one with the highest index. The final element of the path is the name of the Property of which the value -needs to be set. The elements of the path are sufficient to identify the object within the JSON if the value of the corresponding key is -an object. If the value is an array, the appropriate object within the array needs to be selected. -For this selection additional ``FOREIGN`` columns are used. The path given in those columns is the path to the level where the object needs to be chosen plus the name of the attribute that is used to select the correct object. +| date | `coach.family_name` | `coach.given_name` | +|------------|---------------------|--------------------| +| 2023-01-01 | Sky | Max | +| 2023-01-01 | Sky | Min | + +## Data in XLSX: Hidden automation logic ## + +### First column: Marker for row types ### + +The first column in each sheet will be hidden and it will contain an entry in each row that needs +special treatment. The following values are used: + +- ``IGNORE``: This row is ignored. It can be used for explanatory texts or layout. +- ``COL_TYPE``: Typically the first row that is not `IGNORE`. It indicates the row that defines the + type of columns (`FOREIGN`, `SCALAR`, `LIST`, `IGNORE`). This row may occur only once. +- ``PATH``: Indicates that the row is used to define the path within the JSON. These rows are + typically hidden for users. + +An example table could look like this: + +| `IGNORE` | | Welcome | to this | file! | | +| `IGNORE` | | Please | enter your | data here: | | +| `COL_TYPE` | `IGNORE` | `SCALAR` | `SCALAR` | `LIST` | `SCALAR` | +| `PATH` | | `Training` | `Training` | `Training` | `Training` | +| `PATH` | | `url` | `date` | `subjects` | `supervisor` | +| `PATH` | | | | | `email` | +| `IGNORE` | Please enter one training per line. | Training URL | Training date | Subjects | Supervisor's email | +|------------|-------------------------------------|----------------|---------------|--------------|--------------------| +| | | example.com/mp | 2024-02-27 | Math;Physics | steve@example.com | +| | | example.com/m | 2024-02-27 | Math | stella@example.com | + +### Parsing XLSX data ### + +To extract the value of a given cell, we traverse all path elements (in ``PATH`` rows) from top to +bottom. The final element of the path is the name of the Property to which the value belongs. In +the example above, `steve@example.com` is the value of the `email` Property in the path +`["Training", "supervisor", "email"]`. + +The path elements are sufficient to identify the object within a JSON, at least if the corresponding +JSON element is a single object. If the JSON element is an array, the appropriate object within the +array needs to be selected. + +For this selection additional ``FOREIGN`` columns are used. The paths in these columns must all have +the same *base* and one additional *unique key* component. For example, two `FOREIGN` columns could +be `["Training", "date"]` and `["Training", "url"]`, where `["Training"]` is the *base path* and +`"date"` and `"url"` are the *unique keys*. + +The base path defines the table (or recordtype) to which the entries belong, and the values of the +unique keys define the actual rows to which data belongs. + +For example, this table defines three coaches for the two trainings from the last table: + +| `COL_TYPE` | `FOREIGN` | `FOREIGN` | `SCALAR` | +| `PATH` | `Training` | `Training` | `Training` | +| `PATH` | `date` | `url` | `coach` | +| `PATH` | | | `given_name` | +| `IGNORE` | Date of training | URL of training | The coach's given name | +| `IGNORE` | from sheet 'Training' | from sheet 'Training' | | +|------------|-----------------------|-----------------------|------------------------| +| | 2024-02-27 | example.com/mp | Ada | +| | 2024-02-27 | example.com/mp | Berta | +| | 2024-02-27 | example.com/m | Chris | diff --git a/unittests/table_json_conversion/how_to_schema b/unittests/table_json_conversion/how_to_schema.md similarity index 100% rename from unittests/table_json_conversion/how_to_schema rename to unittests/table_json_conversion/how_to_schema.md -- GitLab