Skripte und XML-Code


Namensgebung bei Skripten

HINWEIS
Im Folgenden ist mit "Name eines Skriptes" immer die Id gemeint.

  • Namen von Skripten müssen gut überlegt gesetzt werden, da sie als eindeutiges Identifikationsmerkmal dienen. Wenn sich ein Skript einmal in einer Vorlage befindet, bewirkt eine Änderung des Namens, dass das Skript neu eingefügt werden muss.

  • Skript-Namen beschreiben bestenfalls die Ausgabe. So ist "LocationDate" sinnvoller als "LetterStart".

  • Skript-Namen sollten aber auch möglichst simpel und allgemein vergeben werden. So ist "Author" sinnvoller als "ReportAuthor".

    Oftmals kann die Ausgabe aber nicht beschrieben werden, da sie sich unter Umständen durch spezifische Bedingungen völlig verändert. In diesem Fall darf der Ort des Skripte im Dokument als Name gesetzt werden (z. B. "Footer1stPage").

  • Skript-Namen werden mittels "Pascal Casing" formatiert. Das bedeutet, dass der Anfangsbuchstabe und jeder Wort-Anfangsbuchstabe immer gross sind.

    Beispiele:

    • ContactInformation

    • LocationDate

  • Skript-Namen dürfen keine Umlaute (äöü) und keine Sonderzeichen ausser "_" (Underline) enthalten. Punkte dienen zur Einteilung in die Ordnerstruktur.

  • Skript-Namen sind auf 100 Zeichen begrenzt.

  • Die Entwicklungssprache in primedocs ist grundsätzlich Englisch, sowohl im Source Code als auch in den Skripten. Kommentare bilden eine Ausnahme: dort darf auch auf Deutsch geschrieben werden. Kommentare beginnen mit den Zeichen <!-- und enden mit -->.


Globale Konfigurationen

Möglichst global

In den meisten Fällen gilt: je globaler desto besser. Das bedeutet: lieber ein Skript zu viel auslagern als eines zu wenig. Sobald ein Skript mehr als einmal vorkommt, wird es ausgelagert (in die Globalen Konfigurationen eingefügt und verknüpft), damit das Skript nur an einem Ort gepflegt werden muss.

Wenn man ein neues Skript benötigt, das leicht unterschiedlich zu einem existierenden Skript sein soll, erreicht man das auf drei Arten:

1. Bestehendes Skript erweitern

Das bestehende Skript kann so abgeändert werden, dass der gewünschte Unterschied unter einer Bedingung (Condition) zustande kommt. Die Condition könnte z. B. den Status einer nicht-sichtbaren Dokument-Parameter-Checkbox (z. B. DocParam.EnableDateOfInHeader) abfragen oder sich auf den Inhalt eines bestimmten Skript-Namens stützen (z. B. CustomElements.EnableDateOfInHeader = 'true'). Beispiel:

<CustomDataNode id="HeaderAdditionalText"> <Line> <Element id="Org.Unit" /> </Line> <Line> <Text when="DocParam.EnableDateOfInHeader">{D[Texts.DateOf]} </Text> <Element id="DocParam.Date" fFormatingDate="{D[Configuration.DateFormat.WrittenOut]}" /> </Line> </CustomDataNode>

Hier wird (neben der Abteilung auf der 1. Zeile) entweder "vom 1. Januar 2017" oder "1. Januar 2017" ausgegeben, je nach dem, ob DocParam.EnableDateOfInHeader in einer Vorlage aktiviert ist oder nicht.

✔ Wartbarkeit – Da kein zusätzliches Skript erstellt wurde, ist es später einfacher, den Überblick über die Skripte und deren Funktionalitäten zu haben.

❌ Komplexität – Skripte mit Conditions sind anspruchsvoller zu lesen und zu bearbeiten.

2. Vererbung nutzen

Falls ein Skript in der Layoutvorlage entweder geschrieben oder mit den Globalen Konfigurationen verknüpft ist, besteht auch die Möglichkeit, dieses Skript in die Inhaltsvorlage zu kopieren und dort den Inhalt zu ändern. Dann wird der Skriptinhalt folglich durch die Hauptvorlage gesteuert. Dabei muss der Name zwingend gleich bleiben. Die Dokument-Pipeline geht dann bei der Generierung durch alle Skripte durch und wird dann die in der Kette unterste Version des Skriptes nehmen (in diesem Fall in der Inhaltsvorlage). Das geht natürlich auch von Layoutvorlage zu Funktionsvorlage oder von Inhaltsvorlage zu Funktionsvorlage.

✔ Einfachheit – Das Skript wird lediglich kopiert und in die auf der Layoutvorlage basierende Vorlage in der Vorlagenhierarchie eingefügt und angepasst. Der Vorgang ist sehr simpel und unkompliziert.

✔ Wartbarkeit – Soll wieder das globale Skript benutzt werden, wird das überschreibende Skript einfach gelöscht oder auskommentiert.

❌ Komplexität – Für andere Vorlagenbearbeiter kann es schwierig sein, das richtige Skript zu finden, das sie in der Word-Vorlage sehen. Grund dafür ist, dass die Id gleich lautet (was wir mit der Vererbung auch ausnutzen). Sie müssen wissen, dass bei der Generierung effektiv nicht auf das globale Skript sondern auf eine überschreibende Version in der Inhalts- bzw. Funktionsvorlage zugegriffen wird.

3. Kopie erstellen

Im Notfall kann man das Skript kopieren, den Namen des Skripts anpassen und die Änderungen an der Kopie vornehmen. Dieses neue Skript muss dementsprechend in der Vorlage neu eingefügt werden. Der Unterschied zum anderen Skript sollte gut ersichtlich sein (zum Beispiel kann ein Kommentar erfasst werden. Bestenfalls sieht man den Unterschied im Namen).

✔ Schneller – Kopien von Skripten zu erstellen, ist einfacher und geht schneller.

❌ Wartbarkeit – bei vielen ähnlichen Skripte kann leicht die Übersicht verloren gehen. Das insbesondere dann, wenn die Unterschiede der ähnlichen Skripte nicht ersichtlich sind.


Struktur in den Globalen Konfigurationen

Gruppen ("Group")

Neue Skripte werden bei praktisch allen Kundenlösungen in den Globalen Konfigurationen in der Gruppe "Scripts" abgelegt. Neben Skripten können in den Globalen Konfigurationen auch andere Konfigurationen, die häufig verwendet werden, abgelegt werden, wie z. B. Regex-Validierungen, HTML-Bausteine oder Formatierung-Dokumentfunktion-Konfigurationen. Letzteres sollte jedoch wenn möglich immer direkt an die Layout- bzw. Inhaltsvorlage angehängt werden. Solche Skripte gehören dann nicht in die Gruppe "Scripts", sondern in dafür neu angelegte Gruppen. Formatierung-Dokumentfunktion-Konfigurationen gehören beispielsweise in die Gruppe "Formatting".

Namen von Konfigurationsteilen und Skripten

Grundsätzlich haben einzelne Einträge in den Globalen Konfigurationen beim Auslagern genau denselben Namen wie die darin enthaltenen CustomDataNodes. Im folgenden Beispiel, ist die Gruppe "Scripts" und der Eintrag "Salutation" angewählt. Das CustomDataNode hat ebenfalls den Namen "Salutation":

Gruppe Scripts.Salutation: Eintrag

Gruppe Scripts.Salutation: XML

<CustomDataNode id="Salutation"> <Line> <Element id="Contact.Recipient.Selected.Person.Salutation" textafter="{D[Configuration.SalutationSuffix]}" /> </Line> <Line> <Element id="Contact.Recipient.Selected.AdditionalPerson.Salutation" textafter="{D[Configuration.SalutationSuffix]}" /> </Line> </CustomDataNode>

Oft werden jedoch verschiedene Skripte für eine Vorlagengruppe oder für einen Dokumenttyp (Verträge, Briefe, Arbeitszeugnisse, etc.) benötigt. In dem Fall werden diese Skripte alle in einen Eintrag abgespeichert. Die Namen der einzelnen CustomDataNodes sind dann gemäss dem Schema: Eintrag.Name. Im folgenden Fall ist das Signers.Signer_0.

Gruppe Scripts.Signers: Eintrag

Gruppe Scripts.Signers: XML

<CustomDataNode id="Signers.Signer_0.NameLine"> <Element id="Signer_0.User.Title" separator=" "/> <Element id="Signer_0.User.FirstName" separator=" " /> <Element id="Signer_0.User.LastName" /> </CustomDataNode> <CustomDataNode id="Signers.Signer_0.Function"> <Element id="Signer_0.User.Function" /> </CustomDataNode> <CustomDataNode id="Signers.Signer_1.NameLine"> <Element id="Signer_1.User.Title" separator=" " /> <Element id="Signer_1.User.FirstName" separator=" " /> <Element id="Signer_1.User.LastName" /> </CustomDataNode> <CustomDataNode id="Signers.Signer_1.Function"> <Element id="Signer_1.User.Function" /> </CustomDataNode>

Diese Konfiguration wird folglich in den Vorlagen durch {[Scripts.Signers]} integriert. Unter "Inhalt verknüpfen" kann man somit den Ordner "Signers" aufrufen, der vier Skripte enthält. Die Skripte von den Globalen Konfigurationen werden, wenn möglich, in den Layoutvorlagen verknüpft, damit alle anhängenden Inhaltsvorlagen diese Skripte auch zur Verfügung haben. Der Fall, dass nur eine Vorlage eine grosse Anzahl Skripte benötigt, ist relativ selten.

Es gibt einen Fall, in dem es sinnvoll ist, Skripte mit Nummern zu versehen, nämlich wenn je nach Bedingung, verschiedene Inhalte in einer Tabelle stehen und verschieden formatiert werden. Wenn ein Skript also auf mehrere Teil-Skripte aufgeteilt werden muss, ist dieses Skript meistens ausschliesslich für diese Verwendung vorgesehen. Unter dieser Ausnahme macht es keinen Sinn, für jedes Teil-Skript einen beschreibenden Namen zu vergeben.

Ein Beispiel: Nehmen wir an, es wird eine Tabelle erstellt, die fett oder normal formatiert wird. Die Skripte können dann nach Row (=Zeile) und Column (=Spalte) und danach nach fett und nicht fett eingeteilt werden. So weiss man genau, welches Skript in welche Zelle kommt:

  • Protocol.Row1.Col1.bold

  • Protocol.Row1.Col2.normal

  • Protocol.Row2.Col1.bold

  • Protocol.Row2.Col2.normal

  • Protocol.Row3.Col1.bold

  • Protocol.Row3.Col2.normal

 

Das wäre in Word zum Beispiel so:

 

Grundsätzlich sollte der Name gemäss dem Kapitel Namensgebung bei Skripten möglichst beschreibend sein oder in wenigen Fällen die Position beschreiben.


Rekursion in Skripten

Einfache Rekursion

Manchmal macht es Sinn, in einem Skript auf das Resultat eines anderen Skripts zuzugreifen. Wenn z. B. in fünf verschiedenen Skripten der Lösung ermittelt werden muss, ob sich Profil und Signer_1 entsprechen und ob die aktuelle Organisationseinheit nicht das Finanzdepartement ist, kann das über ein Skript ermittelt werden, auf dessen Resultat wir im Anschluss zugreifen:

Beim Verknüpfen von globalen Skripten, die auf andere Logik-Skripte zugreifen, muss darauf geachtet werden, dass das Logik-Skript ebenfalls verknüpft wird. Beispiel, wobei "CompanyAddress" das Resultat des Logik-Skripts benötigt: {[Scripts.Logic.Signer1EqualsProfileAndOuIsNotFinance]}
{[Scripts.CompanyAddress]}


Mehrfache Rekursion (Depth)

Der Zugriff auf ein Resultat eines simplen Skripts funktioniert immer. Der Zugriff auf ein Resultat eines Skripts, das wiederum auf das Resultat eines weiteren Skripts zugreift, wird mit Depth ermöglicht. Das passiert in der Skripte-Dokumentfunktion. Hier ist die Depth auf 5 gesetzt:

Das bewirkt nun, dass die Skript-Resultate 3-mal berechnet werden und folglich, dass der Zugriff eines Skriptes A auf das Resultat eines Skriptes B, das auf das Resultat eines Skripte C zugreift, funktioniert. Die Depth ist in jeder Kundendatenbank folgendermassen in den Globalen Konfigurationen ausgelagert:

In jeder Skripte-Dokumentfunktion sieht die Verknüpfung dann so aus:

Wenn ein Resultat eines Skripts, das auf andere Skripte zugreift, nicht wie erwartet ist, muss überprüft werden,

  • ob das Skript, auf das zugegriffen wird, überhaupt verfügbar / verknüpft ist.

  • ob die Depth mindestens so hoch ist, wie die Anzahl verschachtelter Zugriffe.


Code-Darstellung

Eine Einzugsebene besteht aus 2 Leerzeichen oder einem Tab. Beim Druck der Tab-Taste im primedocs-XML-Editor werden 2 Leerzeichen eingefügt. Wenn mehrere Zeilen markiert sind, kann durch Druck "Tab" und "Shift+Tab" der Einzug der markierten Zeilen vergrössert und verkleinert werden. Folgend ein Beispiel mit korrekten Einzügen:


Globale Konfigurationen

Schöner Code in den Globalen Konfigurationen beinhaltet, dass in einem Eintrag nach jedem "CustomDataNode"-Element ein leerer Absatz folgt. Hier ein Beispiel:


Skripte

CustomDataNodes sind auch hier durch Leerzeilen voneinander sichtbar getrennt. Komplizierte Skripte sowie Conditions in den Skripten sollten in einem einleitenden Kommentar erklärt werden. Bei Conditions kann der Wert des when/notwhen-Attributs Zeilenumbrüche enthalten. Diese verbessern die Lesbarkeit:


Dokument-Parameter

Indem Attribute mit Tabs auf dieselbe Höhe gebracht werden, kann die Übersichtlichkeit erhöht werden:

 

PrimeSoft AG, Bahnhofstrasse 4, 8360 Eschlikon, Switzerland