Importmodul IV: Importprofil

Komplexe Deklarationen und Bedingungen

Quellspalten

Verknüpfen von Quellspalten

Die Exportdateien mancher Datenquellen (zum Beispiel das von recotech eingesetzte und empfohlene hylasFM zur Gebäudemodellierung) verwenden bei jedem Export neu erstellte fortlaufende Nummern als Fremdschlüssel. Diese sind nur genau innerhalb eines exportierten Datenpakets eindeutig. Damit sind sie als XIds unbrauchbar, müssen aber trotzdem verwendet werden, um die Verweise zwischen den zu importierenden Datensätzen aufzulösen. Die Behandlung solcher Fremdschlüsselbeziehungen beim Datenextraktionsprozess soll an einem Beispiel erläutert werden.

Die folgenden Tabellen stellen Auszüge aus vier Quelldateien dar, deren Daten für die Importtabelle der Räume relevant sind und deren Datensätze über Fremdschlüssel verknüpft sind.

Räume


Etagen


Gebäude


Standorte

Nr

Name

Etage


Nr

Name

Gebäude


Nr

Name

Standort


Nr

Name

1

R001

1


1

EG

1


1

Müllerstr 4

1


1

Berlin

2

R002

1


2

OG1

1


2

Müllerstr 5

1




3

R101

2


3

EG

2








4

R102

2


4

OG1

2








5

R001

3












6

R002

3












7

R101

4












8

R102

4













Fremdschlüssel

In Datenstrukturen ist ein Fremdschlüssel eine Methode, im Datensatz eines Objektes auf ein anderes Objekt zu verweisen. Ein Raum ist zum Beispiel Teil eines Geschosses. Um zu speichern zu welchem Geschoss ein Raum gehört, wird der Schlüssel des Geschosses (dessen ID) am Raumdatensatz als Fremdschlüssel gespeichert. Das Geschoss ist wiederum Teil eines Gebäudes. Dementsprechend wird am Geschossdatensatz die ID des übergeordneten Gebäudes als Fremdschlüssel gespeichert, genauso mit dem Gebäude und seinem Standort.

Der Name des Gebäudes zu einem bestimmten Raum findet sich dann wie folgt: der Fremdschlüssel des Geschosses im Raumdatensatz muss in genau einem Geschossdatensatz als ID vorkommen. In diesem Datensatz gibt es den Fremdschlüssel eines Gebäudes. Dieser muss wiederum in genau einem Gebäudedatensatz als ID vorkommen. Der gesuchte Gebäudename ist der Name in diesem Datensatz.

In den obigen Beispielen stehen die IDs des Objekte in den Spalten Nr. Dort müssen sie eindeutig sein. Sie tauchen aber ebenfalls in einer Spalte der jeweils links stehenden Tabelle auf. Dort müssen sie nicht eindeutig sein, da mehrere der jeweils links stehenden Objekte zu einem übergeordneten gehören können.

Die entsprechenden Spalten der Raum-Importtabelle sollen nach der Datenextraktion folgendermaßen gefüllt sein:

Name

Geschoss Name

Gebäude Name

Standort Name

R001

EG

Müllerstr 4

Berlin

R002

EG

Müllerstr 4

Berlin

R101

OG1

Müllerstr 4

Berlin

R102

OG1

Müllerstr 4

Berlin

R001

EG

Müllerstr 5

Berlin

R002

EG

Müllerstr 5

Berlin

R101

OG1

Müllerstr 5

Berlin

E102

OG1

Müllerstr 5

Berlin


Um die Tabelle genauso zu füllen, würde man folgendes Verfahren anwenden:

    1. Nimm einen Datensatz DR in der Raumtabelle.
    2. In die Spalte Name schreibe den Wert von DR im Feld Name.
    3. Suche in der Etagen-Tabelle den Datensatz DE, der im Feld Nr den gleichen Wert hat, wie DR im Feld Etage.
    4. In die Spalte Geschoss Name schreibe den Wert des Datensatzes DE im Feld Name.
    5. Suche in der Gebäude-Tabelle den Datensatz DG, der im Feld Nr den gleichen Wert hat wie DE im Feld Gebäude.
    6. In die Spalte Gebäude Name schreibe den Wert von DG im Feld Name.
    7. Suche in der Standort-Tabelle den Datensatz DS, der im Feld Nr den gleichen Wert hat wie DG im Feld Standort.
    8. In die Spalte Standort Name schreibe den Wert von DS im Feld Name.

Wie man sieht, gibt es in diesem Verfahren nur zwei verschiedene Schritte, die jeweils abwechselnd durchgeführt werden. Entweder springt man in einem Datensatz in ein anderes Feld (behält den Datensatz und ändert den Wert) oder man sucht einen Datensatz in der nächsten Datei (d.h. man behält den Wert und ändert den Datensatz).  

Die entsprechenden Deklarationen in der Profildatei für das obige Beispiel würden wie folgt aussehen:

28

$TargetColumn Name

29

Räume.Name

30


30

$TargetColumn FloorName

31

Räume.Etage > Etagen.Nr > Etagen.Name

32


33

$TargetColumn BuildingName

34

Räume.Etage > Etagen.Nr > Etagen.Gebäude > Gebäude.Nr > Gebäude.Name

35


36

$TargetColumn SiteName

37

Räume.Etage > Etagen.Nr > Etagen.Gebäude > Gebäude.Nr >


                    Gebäude.Standort > Standorte.Nr > Standorte.Name

Das Importmodul kontrolliert beim Auswerten der Profildatei, dass die Abfolge der angegebenen Dateien sinnvoll ist. Jeweils die zweite und dritte, die vierte und fünfte usw. angegebene Quellspalte müssen aus der gleichen Datei sein. Dass die zu suchenden Werte in der zweiten, vierten, sechsten usw. Spalte höchstens einmal vorkommen, kann erst nach dem Einlesen der Dateien kontrolliert werden. Wenn ein Fremdschlüssel nicht gefunden wird, ist das Ergebnis in dieser Zeile die leere Zeichenkette. Kommt er mehrfach vor, gilt dies als Fehler, der die Datenextraktion abbricht.

Standartwerte per Verknüpfung prüfen

Eine weitere Anwendung der Verknüpfung von Quellspalten ist folgende:

Angenommen, die Daten für die Platzansprüche und die Platzanspruchstypen sind in zwei Quelldateien, Stellen und Position:


Stellen


Position

Name

Stelle

Fläche

Einzelplatz


Bezeichnung

Anspruch

Einzelplatz

HR_1

Sachbearbeiter

10

nein


Sachbearbeiter

10

nein

HR_2

Sachbearbeiter

10

nein


Abteilungsleiter

15

ja

HR_3

Sachbearbeiter

10

nein





HR_Leiter

Abteilungsleiter

15

ja





Sales_1

Sachbearbeiter

10

nein





Sales_2

Sachbearbeiter

12

ja





Bis auf die letzte aufgelistete Stelle entsprechen alle bezüglich Flächenanspruch und Einzelplatz-Privileg dem Standard (grüner Hintergrund). In die Felder Größe und Einzelplatz der Platzanspruchstabelle sollte also bei fast allen nichts (bzw. der Wert des NullString-Schlüssels) stehen, damit sie nicht nur faktisch die Standardwerte haben, sondern so definiert sind, dass sie ihre Werte auch vom Standard beziehen. Nur der letzte Datensatz weicht vom Standard ab, so dass der daraus generierte Platzanspruch explizit gesetzte Werte haben sollte.

Folgende Deklarationen ersetzen bei der Zuordnung zur Zielspalte alle Standardwerte durch den NullString.

Beide leisten genau das Gleiche, im ersten Fall sind die logischen Zwischenschritte in eigenen Deklarationszeilen, im zweiten ist die gleiche Deklaration in komprimierter Form verwendet.

30

$SourceColumn EP_bei_Position Stellen.Stelle > Position.Bezeichnung >


                                                  Position.Einzelplatz

31


32

$SourceColumn EP_oder_Nix FullReplace(Stellen.Einzelplatz, NullString,


                                EP_bei_Position = Stellen.Einzelplatz)

33


34

$TargetColumn SingleRight

35

EP_oder_Nix

Die entsprechenden Deklarationen für die Größe:

37

$TargetColumn Size

38

FullReplace(Stellen.Fläche, NullString,


       (Stellen.Stelle > Position.Bezeichnung > Position.Anspruch)


                                                 = Position.Anspruch))

39


Ersetzung mit regulären Ausdrücken

Für gezielte Ersetzungsoperationen in Zeichenketten sind die beiden obigen Ersetzungsdefinitionen oft unzureichend. Deshalb gibt es die Möglichkeit, eine Ersetzung mit regulären Ausdrücken zu verwenden. Reguläre Ausdrücke sind Zeichenketten in einer Metasprache, die Mengen von Zeichenketten in einer Objektsprache beschreiben. Sie können zur Suche und Ersetzung in Texten der Objektsprache eingesetzt werden.
Dieses Dokument ist nicht geeignet, eine Einführung in die Verwendung von regulären Ausdrücken zu geben. Das folgende Beispiel kann nur einen Eindruck vermitteln, was mit regulären Ausdrücken möglich ist und die Syntax der Profildatei beschreiben.

Angenommen, in einer Quelldatei sind in einer Spalte Nutzungsarten nach DIN277 angegeben, allerdings nicht in einheitlicher Schreibweise, sondern wie folgt:

Nutzungsart

NF2.1 – Büro

Büro (NF2.1)

Aufzugs- und Förderanlagen - TF8.6

Flure / Hallen - VF9.1

TF8.6 (Aufzug)

In die Zieltabelle sollen die Bezeichnungen der Nutzungsart im Format der ersten Zeile stehen. Mit der Verwendung von regulären Ausdrücken ist das zum Beispiel wie folgt möglich:

Zunächst wird eine Quellspalte Din277 definiert, die nur das Kürzel enthält:

42

$SourceColumn Din277 RegexReplace(Raum.Nutzungsart,


                               "^.*([NVT]F\d+\.\d+).*$", "$1")

43


Zur Erläuterung:  

RegexReplace leitet die Definition ein. In Klammern und mit Kommata getrennt erwartet das Importmodul drei Angaben: die als Vorlage dienende Quellspalte und zwei reguläre Ausdrücke; zunächst das, was ersetzt werden soll und dann wodurch es ersetzt werden soll. Die hier verwendeten regulären Ausdrücke bedeuten im Detail folgendes:

    • Einen regulären Ausdruck mit ^ zu beginnen und mit $ zu beenden bedeutet, dass dieser auf die ganze Zeichenkette passen soll.
    • [NVT] bedeutet: eines der Zeichen N, V oder T
    • F steht für genau diesen Buchstaben
    • \d steht für ein numerisches Zeichen
    • + steht für: das vorhergehende Zeichen mindestens einmal
    • \. steht für einen Punkt. Das Escape Zeichen ist notwendig, weil der Punkt ansonsten für irgendein Zeichen steht. So wie am Anfang und Ende des Ausdrucks '.*' für beliebiges Zeichen beliebig oft steht.
    • * bedeutet: das vorhergehende Zeichen beliebig oft, d.h. auch 0 mal
    • Die Klammern um [NVT]F\d+\.\d+ geben an, dass der Teil der Zeichenkette, der dem entspricht, in der Ersetzungsklausel mit '$1' benannt zur Verfügung stehen soll. Ein zweiter Teil in Klammern würde mit '$2' adressiert werden können.

Insgesamt bedeutet die Deklaration in Worten: nimm den ganzen Wert, suche darin den Teil, der mit N, V oder T anfängt, dann ein F, eine Zahl, einen Punkt und noch eine Zahl hat. Nimm nur diesen Teil.

Die neu definierte Spalte Din277 hat folgende Werte:

Nutzungsart

Din277

NF2.1 – Büro

NF2.1

Büro (NF2.1)

NF2.1

Aufzugs- und Förderanlagen - TF8.6

TF8.6

Flure / Hallen - VF9.1

VF9.1

TF8.6 (Aufzug)

TF8.6

Als nächstes definiert man eine neue Spalte, die den Rest enthält:

44

$SourceColumn Rest RegexReplace(Raum.Nutzungsart,


                               "(.*)" + Din277 + "(.*)", "$1$2")

45


In diesem Fall wird keine konstante Zeichenfolge als regulärer Ausdruck verwendet, sondern eine durch Verkettung definierte Quellspalte. In dieser Deklaration wird also für jede Zeile ein anderer regulärer Ausdruck verwendet. Insgesamt bedeutet dies: Suche den Wert, der in der Quellspalte Din277 an gleicher Position steht. Alles was davor kommt, sei der erste später zu verwendende Teil, alles was danach kommt der zweite. Nimm diese beiden Teile und hänge sie hintereinander.

Die neu definierte Spalte Rest hat folgende Werte:

Nutzungsart

Din277

Rest

NF2.1 – Büro

NF2.1

– Büro

Büro (NF2.1)

NF2.1

Büro ()

Aufzugs- und Förderanlagen - TF8.6

TF8.6

Aufzugs- und Förderanlagen -

Flure / Hallen - VF9.1

VF9.1

Flure / Hallen -

TF8.6 (Aufzug)

TF8.6

(Aufzug)

Um die Klammern und Bindestriche zu entfernen definiert man:

$SourceColumn RestOhneSonderzeichen RegexReplace(Rest, "[()-]", "")

Die Werte in der Quellspalte RestOhneSonderzeichen sind also die der Quellspalte Rest, allerdings werden runde Klammern und Bindestriche durch die leere Zeichenkette ersetzt, d.h. entfernt. Jetzt stören nur noch die Leerzeichen am Anfang und Ende:

48

$SourceColumn Bezeichnung RegexReplace(RestOhneSonderzeichen,


                                                 "^\s*(.*)\s*$", "$1")

\s steht für ein beliebiges Leerzeichen, \s* steht für beliebig viele Leerzeichen. Der reguläre Ausdruck bedeutet also: Teile die Zeichenkette in drei Teile ein. Der erste umfasst alle Leerzeichen am Anfang, der dritte alle am Ende und der mittlere den Rest. Nimm nur diesen Rest. Damit hat man die Quellspalten:

Nutzungsart

Din277

Rest

Bezeichnung

NF2.1 – Büro

NF2.1

– Büro

Büro

Büro (NF2.1)

NF2.1

Büro ()

Büro

Aufzugs- und Förderanlagen - TF8.6

TF8.6

Aufzugs- und Förderanlagen -

Aufzugs- und Förderanlagen

Flure / Hallen - VF9.1

VF9.1

Flure / Hallen -

Flure / Hallen

TF8.6 (Aufzug)

TF8.6

(Aufzug)

Aufzug

und kann mit

$SourceColumn NeuesFormat Din277 + " " + Bezeichnung

die gewünschte Quellspalte definieren.

.Net reguläre Ausdrücke

Das Importmodul nutzt die .Net 3.5 Bibliothek für reguläre Ausdrücke. Die Dokumentation dieses Dialekts findet sich im Internet in der MSDN Library unter dem Suchbegriff 'reguläre Ausdrücke'.

Eine Quellspaltendefinition mit RegexReplace lässt sich optional noch um eine Bedingung erweitern. Diese wird dann als vierter Parameter übergeben und bewirkt, dass die Ersetzung nur in den Zeilen ausgeführt wird, in denen die Bedingung erfüllt ist.

Quellbedingungen

Die einfachsten Bedingungen, Tests auf Gleichheit oder Ungleichheit, wurden schon oben erwähnt. Zusätzlich gibt es zwei weitere Grundbausteine für Bedingungen und die Möglichkeit, logische Funktionen mit diesen zu definieren. Insbesondere wegen der beliebigen Schachtelungstiefe der letzteren können auch Quellbedingungen mit einem Alias versehen werden. Der entsprechende Schlüssel ist SourceCondition. Genau wie bei den Quellspalten erwartet das Importmodul nach diesem Schlüssel einen Alias und dann die Definition der Quellbedingung.

Zeichenkettenvergleich mit Wildcards

Statt direkt auf Gleichheit oder Ungleichheit zu testen, können Suchmuster mit Wildcard-Symbolen verwendet werden. Ein Wildcard-Symbol steht für eine beliebige Zeichenkette.

Mit einer solchen Bedingung kann zum Beispiel die Erzeugung von Raumzonen in der Importtabelle der Räume gesteuert werden:

$SourceCondition IstBüro StringMatch(Raum.Nutzungsart, "*büro*")


$SourceColumn ErzeugeRaumzone FullReplace("nein", "ja", IstBüro) 


$TargetColumn CreateRoomZone

ErzeugeRaumzone

Die StringMatch Quellbedingung ignoriert Groß- und Kleinschreibung. Für alle Büros und Großraumbüros würde dem Importmodul befohlen, eine Raum Zone zu erstellen.

Das hier verwendete Wildcard-Symbol ist immer das Zeichen *. Es hat mit dem Wert im Schlüssel WildCardString nichts zu tun.  

Zeichenkettenvergleich mit regulärem Ausdruck

Die ungleich flexiblere Alternative zum Wildcard-Suchmuster sind reguläre Ausdrücke. Die obige Bedingung mit regulärem Ausdruck hätte die folgende Deklaration:

$SourceCondition IstBüro RegexMatch(Raum.Nutzungsart, "^.*[bB]üro.*$")


$SourceColumn ErzeugeRaumzone FullReplace("nein", "ja", IstBüro


$TargetColumn CreateRoomZone

ErzeugeRaumzone

Klammern

Die Definition einer Quellbedingung kann in runde Klammern eingeschlossen werden, ohne dass sich ihre Bedeutung ändert. Die Klammerung bestimmt bei längeren verschachtelten Definitionen nur die Reihenfolge, in der die Bedingungen ausgewertet werden.

Negation

Die Definition einer Quellbedingung um ein Ausrufezeichen am Anfang ergänzt, negiert diese.

Aussagenlogische Formeln

Mit beliebigen Definitionen von Quellbedingungen lassen sich aussagenlogische Ausdrücke konstruieren, die wiederum Quellbedingungen definieren. Angenommen, eine Quelldatei mit dem Alias Flächen enthält die folgende Spalte mit dem Alias Bezeichnung:

Büroraum (NF2.1)

Großraumbüro (NF2.2)

Besprechungsraum (NF2.3)

Konstruktionsraum (NF2.4)

Schalterräum (NF2.5)        

Bedienungsräum (NF2.6)

Aufsichtsräum (NF2.7)

Bürotechnikräum (NF2.8)

Sonstige Bürofläche (NF2.9)

Diese Spalte soll für die Namensspalte der Nutzungsarten-Importtabelle herangezogen werden. In der Datei sind aber keine Angaben über die für recotech wichtige Nutzbarkeit einer Flächenart. Nutzbar sollen nur NF2.1, NF2.2 und NF2.9 sein. Mit dem weiter oben bereits angewandten Trick der aufeinander aufbauenden Ersetzungen ließe sich das gewünschte Ergebnis erzielen:

42

$SourceColumn temp1 FullReplace("nein", "ja",


                                 StringMatch(Flächen.DIN277, "*NF2.1*"))

43

$SourceColumn temp2 FullReplace(temp1, "ja",


                                 StringMatch(Flächen.DIN277, "*NF2.2*"))

44

$SourceColumn Nutzbar FullReplace(temp2, "ja",


                                 StringMatch(Flächen.DIN277, "*NF2.9*"))

45


Stattdessen kann man eine einzige Bedingung als logische Disjunktion (logisches Oder) definieren. Das Operatorzeichen der Disjunktion ist der senkrechte Strich:

44

$SourceCondition nutzbar StringMatch(Flächen.DIN277, "*NF2.1*") |


                        StringMatch(Flächen.DIN277, "*NF2.2*") |        


                        StringMatch(Flächen.DIN277, "*NF2.9*")

45

$SourceColumn Nutzbar FullReplace("nein", "ja", nutzbar)

Noch eleganter geht es (wie fast immer) mit regulären Ausdrücken:

44

$SourceColumn Nutzbar FullReplace("nein", "ja",


                        RegexMatch(Flächen.DIN277, "^.*NF2\.[129].*$"))

45


Weitere logische Operationen sind die Konjunktion (logisches Und), die Implikation (logisches Wenn) und die Äquivalenz (logisches Genau-Dann-Wenn). Die folgende Tabelle gibt eine Übersicht über die Wahrheitswerte und die verwendeten Symbole.

C1

C2

C1 & C2

C1 | C2

C1 -> C2

C1 <-> C2

Wahr

Wahr

Wahr

Wahr

Wahr

Wahr

Wahr

Falsch

Falsch

Wahr

Falsch

Falsch

Falsch

Wahr

Falsch

Wahr

Wahr

Falsch

Falsch

Falsch

Falsch

Falsch

Wahr

Wahr


Die aussagenlogischen Operatoren haben wie die Rechenzeichen in der Arithmetik ("Punktrechnung geht vor Strichrechnung") unterschiedliche Priorität. Die Negation bindet am stärksten, gefolgt von der Konjunktion (und), der Disjunktion (oder), der Implikation (wenn dann) und schließlich die Äquivalenz (genau dann wenn). Diese Standard-Reihenfolge ist nur dann entscheidend, wenn keine Klammern gesetzt sind.