Zum Hauptinhalt springen

Spezifikation

Dieses Dokument spezifiziert das JSON-Format, in dem das FIM Portal maschinenlesbare Übersetzungen von XDatenfelder-Regeln bereitstellt. Es ist der Vertrag für alles, was übersetzte Regeln liest – etwa die Formularvorschau des FIM Portals oder Formular-Laufzeiten Dritter.

Entstehung der Übersetzungen​

Regeln in XDatenfelder (xdf2 und xdf3) sind als deutschsprachiger Freitext hinterlegt (freitextRegel), z. B. „Das Feld 'Augenfarbe Person Freitext' ist nur sichtbar und muss ausgefüllt werden, wenn 'Augenfarbe Person' den Wert '98 - Sonstige' hat." Grundlage der Übersetzung ist ausschließlich dieser Freitext, es werden keine Metadaten ausgewertet.

Das FIM Portal übersetzt diese Freitexte in einem automatisierten, KI-gestützten Verfahren in das hier beschriebene Format. Der Ablauf pro regeltragendem Element (Schema, Datenfeldgruppe oder Datenfeld):

  1. Datenstruktur ableiten. Aus dem Element wird eine stark typisierte Beschreibung seiner Kinder erzeugt (Format siehe unten). Sie legt fest, welche Bezeichner in einer Regel überhaupt vorkommen dürfen und welchen Typ sie haben.
  2. Übersetzen. Ein Sprachmodell erhält die Datenstruktur, eine Zuordnung der Kind-IDs zu ihren deutschen Namen und alle Freitextregeln des Elements, jede mit der ID und Version ihrer Regel, und erzeugt daraus je Regel die Rule-Objekte. Kann eine Regel mit den verfügbaren Operationen nicht ausgedrückt werden, wird das Element als „nicht übersetzbar" markiert.
  3. Vollständigkeitsprüfung. Die Regel-IDs des erzeugten Dokuments müssen genau die Regeln des Elements sein: Fehlt eine Regel oder taucht eine fremde ID auf, wird die Übersetzung des gesamten Elements verworfen.
  4. Typprüfung. Jedes erzeugte Rule-Objekt wird gegen die Datenstruktur geprüft: Bezeichner müssen existieren, Operanden die passenden Typen haben, Bedingungen den vom Effekt geforderten Typ liefern. Schlägt die Prüfung für eine Regel fehl, wird die Übersetzung des gesamten Elements verworfen.

Nur Übersetzungen, die die Schritte 3 und 4 bestehen, werden gespeichert und ausgeliefert. Für Elemente ohne gültige Übersetzung gibt es kein Dokument.

Format der Datenstruktur (Basis der Übersetzung)​

Die Datenstruktur ist ein JSON-Objekt, das die Form der Daten eines Elements beschreibt. Jeder Knoten hat ein type-Attribut:

  • Primitive Typen: text, text_latin, date, time, datetime, bool, num, num_int, num_currency, file, obj sowie enum (mit den erlaubten Codes im Attribut values).
  • Komplexe Typen: group bzw. schema (Kinder im Attribut children, Schlüssel = Kind-ID), array (Eintragstyp in value, optional min_items / max_items) und optional (innerer Typ in value).

Beispiel für eine Datenfeldgruppe mit einem Pflicht-Textfeld und einem optionalen Codelistenfeld:

{
"type": "group",
"children": {
"F001": { "type": "text" },
"F002": {
"type": "optional",
"value": { "type": "enum", "values": ["01", "02", "98"] }
}
}
}

Die Datenstruktur beschreibt nur die Grundform der Daten. Regeln dürfen diese Form weiter einschränken (z. B. ein optionales Feld bedingt zur Pflicht machen), aber nie lockern.

Auslieferung​

  • Endpunkt: GET /api/v0/translated-rules/{fim_id}/{fim_version} – 200 mit dem unten beschriebenen JSON-Dokument, 404, wenn für das Element keine Übersetzung vorliegt.
  • Der Endpunkt gehört zur v0-API (Beta): Das Format kann sich noch inkompatibel ändern und trägt keine Versionsangabe im Dokument.
  • Ein Dokument pro Element. Wer die Regeln eines ganzen Schemas benötigt, ruft das Schema selbst sowie jede Datenfeldgruppe und jedes Datenfeld ab, das Regeln definiert.

Dokument​

Das Dokument ist ein JSON-Objekt mit einem Schlüssel je Regel des Elements. Der Schlüssel ist <fim_id>:<fim_version> der Regel (bei einer Regel ohne Version <fim_id>:), der Wert das Array der Rule-Objekte, die diese Regel übersetzen. Das Dokument enthält genau die Regeln des Elements, die einen Freitext haben; die Reihenfolge der Schlüssel und der Rule-Objekte ist nicht garantiert.

Ein Freitext kann mehrere Rule-Objekte ergeben (eine Sichtbarkeitsregel mit Pflichtanteil wird zu forbid und require). Ein leeres Array bedeutet, dass die Regel die Datenstruktur nicht weiter einschränkt, etwa weil sie nur verlangt, dass ohnehin verpflichtende Elemente befüllt sind.

{
"R60000012:1.0": [
{
"effect": "require",
"target": "F60000355",
"message": "Das Feld 'Augenfarbe Person Freitext' muss angegeben werden, wenn 'Augenfarbe Person' den Wert '98 - Sonstige' hat.",
"condition": { "equal": [{ "identifier": "F60000281" }, "98"] }
},
{
"effect": "forbid",
"target": "F60000355",
"message": "Das Feld 'Augenfarbe Person Freitext' darf nicht angegeben werden, wenn 'Augenfarbe Person' nicht den Wert '98 - Sonstige' hat.",
"condition": { "not_equal": [{ "identifier": "F60000281" }, "98"] }
}
],
"R60000013:1.0": []
}

Über die Regel-IDs ordnen Konsumenten jedes Rule-Objekt der Freitextregel zu, aus der es entstanden ist. Das Dokument selbst enthält keine Metadaten, keine Herkunftsangabe und keinen Freitext der Originalregel. Den Freitext liefert weiterhin das XDatenfelder-Dokument selbst; die Übersetzung ergänzt ihn, sie ersetzt ihn nicht.

Rule-Objekt​

FeldTypPflichtBedeutung
effect"require" | "forbid" | "value" | "valid"jaWas passiert, wenn die Bedingung erfüllt ist (siehe unten).
targetBezeichner-String (siehe Bezeichner)require/forbid/value: ja; valid: muss fehlenDas Kindelement, auf das der Effekt wirkt.
conditionExpressionjaWird gegen die Daten des Elements ausgewertet; der geforderte Typ hängt vom effect ab.
messageString (Deutsch)jaFür Nutzer lesbarer Text, der bei Verletzung der Regel angezeigt wird.

Konsumenten müssen unbekannte zusätzliche Schlüssel ignorieren; der Erzeuger gibt derzeit keine aus.

Effekte​

EffektTyp der BedingungSemantik
requirebooleanIst die Bedingung true, muss target vorhanden (nicht leer) sein. target muss ein optional-Kind oder ein array-Kind mit min_items = 0 sein.
forbidbooleanIst die Bedingung true, darf target nicht vorhanden sein. Gleiche Einschränkungen für das Ziel wie bei require. Formular-Laufzeiten blenden verbotene Elemente aus – so werden Sichtbarkeitsregeln („nur sichtbar, wenn …") ausgedrückt.
valueTyp von targetSetzt target auf das Ergebnis der Bedingung. Reserviert: Die Übersetzung ist angewiesen, diesen Effekt nicht zu erzeugen, und die aktuelle Laufzeit unterstützt ihn nicht. Konsumenten dürfen ihn ablehnen oder ignorieren.
validbooleanDie Bedingung muss true sein, sonst ist das Element als Ganzes ungültig. Kein target.

Mehrere require- bzw. forbid-Regeln auf dasselbe Ziel sind zulässig: Das Ziel ist erforderlich bzw. verboten, sobald die Bedingung mindestens einer dieser Regeln erfüllt ist. Ist ein Ziel danach gleichzeitig erforderlich und verboten, widersprechen sich die Regeln; die Referenzlaufzeit bricht die Auswertung des Dokuments dann mit einem Fehler ab.

Eine Regel lockert niemals eine Einschränkung, die die Datenstruktur selbst definiert.

Bezeichner und Geltungsbereich​

Alle Bezeichner eines Dokuments werden relativ zu dem Element aufgelöst, zu dem das Dokument gehört (sein Geltungsbereich): das Schema bei einer Schema-Übersetzung, die Gruppe bei einer Datenfeldgruppen-Übersetzung, das Feld bei einer Datenfeld-Übersetzung. Übersetzungen sind damit pro Element in sich geschlossen und wissen nichts über das Schema, in das sie eingebettet sind.

  • Ein Bezeichner ist ein durch Punkte getrennter Pfad aus Kind-IDs, z. B. "F001", "G60000012.F60000231". Kind-IDs sind die FIM-IDs ohne Version (F… für Datenfelder, G… für Datenfeldgruppen).
  • Das Präfix self bezeichnet das Element des Geltungsbereichs und ist vor einem Pfad optional: "self.F001" ≡ "F001". Ein bloßes "self" verweist auf den Wert des Elements selbst (nur bei einem Datenfeld als Geltungsbereich sinnvoll).
  • Gespeicherte Dokumente enthalten keine numerischen (Array-Index-)Pfadsegmente; Array-Einträge werden über map adressiert.
  • Innerhalb von map werden Bezeichner relativ zum aktuellen Array-Eintrag aufgelöst.
  • Ein target ist ein Bezeichner-String; innerhalb von condition ist ein Bezeichner das Objekt { "identifier": "<pfad>" }.

Ausdrucksgrammatik​

Ausdrücke sind JSON-Werte. Jede Operation ist ein Objekt mit genau einem Schlüssel, der die Operation benennt. Operandentypen werden gegen die Datenstruktur des Elements geprüft (siehe Format der Datenstruktur oben) – ein ausgeliefertes Dokument hat diese Prüfung bestanden.

type Expression = Literal | Identifier | Operation;

// Literals. Bare JSON string/boolean/number are text/bool/num;
// the wrapped forms carry the more specific XDF data types.
// text_latin, file and obj values are compared as plain text.
// date, time and datetime are reserved: the runtime supports
// them, but the translation does not emit them yet (see below).
type Literal =
| string
| boolean
| number
| { num_int: number }
| { num_currency: number }
| { date: string } // ISO 8601 date, e.g. "2024-01-31"
| { time: string } // ISO 8601 time
| { datetime: string }; // ISO 8601 date-time

type Identifier = { identifier: string };

type Operation =
| LogicalOperation
| ArithmeticOperation
| ComparisonOperation
| StringOperation
| OptionalOperation
| ArrayOperation
| DateOperation
| DomainSpecificOperation;

type LogicalOperation =
| { and: Expression[] }
| { or: Expression[] }
| { xor: Expression[] }
| { not: Expression };

type ArithmeticOperation =
| { add: Expression[] }
| { subtract: [Expression, Expression] }
| { multiply: Expression[] }
| { divide: [Expression, Expression] };

// Ordered comparisons work on two numbers or two values of the same
// date/time type (e.g. a date field against `today`).
type ComparisonOperation =
| { equal: [Expression, Expression] }
| { not_equal: [Expression, Expression] }
| { less_than: [Expression, Expression] }
| { greater_than: [Expression, Expression] }
| { less_equal: [Expression, Expression] }
| { greater_equal: [Expression, Expression] };

type StringOperation =
| { contains: [Expression, Expression] } // haystack, needle
| { starts_with: [Expression, Expression] }
| { ends_with: [Expression, Expression] }
| { string_length: Expression } // number of characters
| { matches_pattern: [Expression, Expression] }; // value, ECMAScript regex literal

type OptionalOperation =
| { is_empty: Identifier }; // operand must be `optional`

type ArrayOperation =
| { length: Identifier } // number of items
| { map: { array: Expression; expression: Expression } } // per-item, item-scoped identifiers
| { any: Expression } // boolean array → true if any item true
| { all: Expression }; // boolean array → true if all items true

type DateOperation =
| { today: {} } // current date
| { age_in_years: Expression }; // full years between a date and today

type DomainSpecificOperation =
| { is_valid_iban: Expression }
| { is_valid_bic: Expression }
| { is_valid_email: Expression }
| { is_valid_date: [Expression, Expression, Expression] }; // day, month, year integers

Erläuterung der Grammatik​

Ein Ausdruck (Expression) ist entweder ein Literal, ein Bezeichner oder eine Operation. Operationen können beliebig geschachtelt werden; jeder Operand ist selbst wieder ein Ausdruck. Die Grammatik ist bewusst nicht Turing-vollständig: Sie enthält nur einfache logische, arithmetische, Vergleichs- und Zeichenkettenoperationen sowie wenige fachliche Prüfungen.

Jeder Abschnitt zeigt vollständige Rule-Objekte, so wie sie in einem ausgelieferten Dokument stehen. Die Feld-IDs sind fiktiv; angenommen werden ein optionales Textfeld F001, ein Zahlenfeld F002, ein Codelistenfeld F003, ein Datumsfeld F004, ein boolesches Feld F005, ein weiteres optionales Textfeld F006, ein weiteres Zahlenfeld F007, drei Ganzzahlfelder F020–F022 (Tag, Monat, Jahr), eine wiederholbare Gruppe G001 mit einem Zahlenfeld F010 und einem optionalen Feld F011 sowie eine nicht wiederholbare Untergruppe G002 mit einem optionalen Textfeld F030.

Literale​

Ein nacktes JSON-string, boolean oder number steht für die XDF-Datentypen Text, Wahrheitswert bzw. Zahl. Die umschlossenen Formen tragen den genaueren Datentyp: num_int (Ganzzahl), num_currency (Geldbetrag), date, time, datetime (jeweils als ISO-8601-String). Werte der Typen text_latin, file und obj haben keine eigene Literalform und werden als Text verglichen.

Die Formen date, time und datetime sind reserviert und beschreiben das Zielbild: Die Referenzlaufzeit unterstützt sie bereits, die Übersetzung erzeugt sie derzeit jedoch nicht – Regeln, die ein solches Literal benötigen, gelten heute als nicht übersetzbar und kommen in ausgelieferten Dokumenten nicht vor. Datumsregeln ohne festes Stichtags-Literal sind über today und age_in_years ausdrückbar (siehe Datumsoperationen).

„Der Betrag (F002) darf 500,00 € nicht überschreiten."

{
"effect": "valid",
"message": "Der Betrag darf 500,00 € nicht überschreiten.",
"condition": { "less_equal": [{ "identifier": "F002" }, { "num_currency": 500.0 }] }
}

„Das Datum (F004) muss nach dem 31.12.2023 liegen." – Zielbild: nutzt das reservierte date-Literal.

{
"effect": "valid",
"message": "Das Datum muss nach dem 31.12.2023 liegen.",
"condition": { "greater_than": [{ "identifier": "F004" }, { "date": "2023-12-31" }] }
}

Bezeichner​

Bezeichner (Identifier) verweisen auf den Wert eines Elements der Datenstruktur, siehe Abschnitt Bezeichner und Geltungsbereich. self. ist optional; verschachtelte Kinder werden über den Punktpfad angesprochen.

„Wenn 'Zustimmung' (F005) angekreuzt ist, muss 'Kontakt-E-Mail' (F001) angegeben werden."

{
"effect": "require",
"target": "F001",
"message": "Die Kontakt-E-Mail muss angegeben werden, wenn die Zustimmung erteilt wurde.",
"condition": { "identifier": "F005" }
}

„Wenn in der Meldeadresse (G002) ein Ortsteil (F030) angegeben ist, muss die Bemerkung (F006) angegeben werden." – der Punktpfad adressiert das Feld in der Untergruppe; das führende self. ist optional.

{
"effect": "require",
"target": "F006",
"message": "Die Bemerkung muss angegeben werden, wenn ein Ortsteil eingetragen ist.",
"condition": { "not": { "is_empty": { "identifier": "self.G002.F030" } } }
}

Einträge einer wiederholbaren Gruppe sind nicht einzeln adressierbar; Regeln darüber nutzen map (siehe Array-Operationen).

Logische Operationen​

and, or, xor und not verknüpfen boolesche Ausdrücke. and, or und xor nehmen eine Liste beliebiger Länge, not genau einen Operanden.

„Wenn 'Rechtsform' (F003) den Wert '01' oder '02' hat, muss 'Handelsregisternummer' (F001) angegeben werden."

{
"effect": "require",
"target": "F001",
"message": "Die Handelsregisternummer muss angegeben werden, wenn die Rechtsform 'GmbH' oder 'AG' ist.",
"condition": {
"or": [
{ "equal": [{ "identifier": "F003" }, "01"] },
{ "equal": [{ "identifier": "F003" }, "02"] }
]
}
}

„Es muss entweder eine IBAN (F001) oder eine Kontonummer (F006) angegeben werden, nicht beides."

{
"effect": "valid",
"message": "Es muss entweder eine IBAN oder eine Kontonummer angegeben werden.",
"condition": {
"xor": [
{ "not": { "is_empty": { "identifier": "F001" } } },
{ "not": { "is_empty": { "identifier": "F006" } } }
]
}
}

„Wenn 'Zustimmung' (F005) nicht erteilt ist und 'Rechtsform' (F003) den Wert '01' hat, darf 'Bemerkung' (F006) nicht angegeben werden."

{
"effect": "forbid",
"target": "F006",
"message": "Die Bemerkung darf ohne Zustimmung bei Rechtsform 'GmbH' nicht angegeben werden.",
"condition": {
"and": [
{ "not": { "identifier": "F005" } },
{ "equal": [{ "identifier": "F003" }, "01"] }
]
}
}

Arithmetische Operationen​

add und multiply rechnen über eine Liste, subtract und divide über genau zwei Operanden. Das Ergebnis ist eine Zahl und wird üblicherweise in einem Vergleich verwendet.

„Der Gesamtbetrag (F002) zuzüglich 19 % Umsatzsteuer darf 1.000 nicht überschreiten."

{
"effect": "valid",
"message": "Der Gesamtbetrag inklusive Umsatzsteuer darf 1.000 nicht überschreiten.",
"condition": {
"less_equal": [
{ "multiply": [{ "identifier": "F002" }, 1.19] },
1000
]
}
}

„Die Differenz aus 'Anzahl Plätze' (F002) und 'Anzahl belegte Plätze' (F007) darf nicht negativ sein."

{
"effect": "valid",
"message": "Es dürfen nicht mehr Plätze belegt sein als vorhanden.",
"condition": {
"greater_equal": [
{ "subtract": [{ "identifier": "F002" }, { "identifier": "F007" }] },
0
]
}
}

Vergleichsoperationen​

Vergleiche nehmen genau zwei Operanden und liefern einen Wahrheitswert. equal und not_equal funktionieren für alle Typen; die geordneten Vergleiche (less_than, greater_than, less_equal, greater_equal) für zwei Zahlen oder zwei Werte desselben Datums-/Zeittyps (z. B. ein Datumsfeld gegen today). Codelistenwerte werden gegen ihren Code verglichen.

„Das Feld 'Sonstige Staatsangehörigkeit' (F001) ist nur sichtbar und muss ausgefüllt werden, wenn 'Staatsangehörigkeit' (F003) den Wert '99 - Sonstige' hat." – ergibt zwei Regeln auf dasselbe Ziel:

[
{
"effect": "require",
"target": "F001",
"message": "Die sonstige Staatsangehörigkeit muss angegeben werden, wenn 'Sonstige' ausgewählt ist.",
"condition": { "equal": [{ "identifier": "F003" }, "99"] }
},
{
"effect": "forbid",
"target": "F001",
"message": "Die sonstige Staatsangehörigkeit darf nur angegeben werden, wenn 'Sonstige' ausgewählt ist.",
"condition": { "not_equal": [{ "identifier": "F003" }, "99"] }
}
]

„Die Anzahl (F002) muss größer als 0 und kleiner als 100 sein."

{
"effect": "valid",
"message": "Die Anzahl muss zwischen 1 und 99 liegen.",
"condition": {
"and": [
{ "greater_than": [{ "identifier": "F002" }, 0] },
{ "less_than": [{ "identifier": "F002" }, 100] }
]
}
}

Zeichenkettenoperationen​

contains, starts_with und ends_with prüfen, ob der erste Text den zweiten enthält bzw. mit ihm beginnt oder endet. string_length liefert die Zeichenzahl eines Textes. matches_pattern prüft einen Text gegen einen regulären Ausdruck; das Muster ist ein String-Literal in ECMAScript-Syntax.

„Wenn 'Postleitzahl' (F001) angegeben ist, muss sie fünfstellig und numerisch sein."

{
"effect": "valid",
"message": "Die Postleitzahl muss aus genau fünf Ziffern bestehen.",
"condition": {
"or": [
{ "is_empty": { "identifier": "F001" } },
{ "matches_pattern": [{ "identifier": "F001" }, "^[0-9]{5}$"] }
]
}
}

„Das Aktenzeichen (F006) muss mit 'AZ-' beginnen und darf höchstens 12 Zeichen lang sein."

{
"effect": "valid",
"message": "Das Aktenzeichen muss mit 'AZ-' beginnen und darf höchstens 12 Zeichen lang sein.",
"condition": {
"and": [
{ "starts_with": [{ "identifier": "F006" }, "AZ-"] },
{ "less_equal": [{ "string_length": { "identifier": "F006" } }, 12] }
]
}
}

„Wenn der Firmenname (F001) 'GmbH' enthält, muss die Handelsregisternummer (F006) angegeben werden."

{
"effect": "require",
"target": "F006",
"message": "Für eine GmbH muss die Handelsregisternummer angegeben werden.",
"condition": { "contains": [{ "identifier": "F001" }, "GmbH"] }
}

Optional-Operation​

is_empty liefert true, wenn ein optionales Element nicht befüllt ist. Der Operand ist immer ein Bezeichner auf ein Element vom Typ optional. Eine „befüllt"-Prüfung ist { "not": { "is_empty": … } }.

„Wenn 'Abweichende Lieferadresse' (F006) befüllt ist, muss 'Empfänger' (F001) angegeben werden."

{
"effect": "require",
"target": "F001",
"message": "Der Empfänger muss angegeben werden, wenn eine abweichende Lieferadresse eingetragen ist.",
"condition": { "not": { "is_empty": { "identifier": "F006" } } }
}

„Wenn keine Kontonummer (F006) angegeben ist, muss die IBAN (F001) angegeben werden."

{
"effect": "require",
"target": "F001",
"message": "Die IBAN muss angegeben werden, wenn keine Kontonummer eingetragen ist.",
"condition": { "is_empty": { "identifier": "F006" } }
}

Array-Operationen​

length liefert die Anzahl der Einträge eines Arrays. map wendet einen Ausdruck auf jeden Eintrag an; Bezeichner innerhalb von expression werden relativ zum jeweiligen Eintrag aufgelöst. any bzw. all liefern true, wenn mindestens ein bzw. jeder Eintrag eines booleschen Arrays true ist – zusammen mit map drücken sie Regeln wie „mindestens eine der Angaben muss …" oder „alle Einträge müssen …" aus.

„Es müssen zwischen einem und drei Kinder (G001) angegeben werden, und für jedes Kind muss der Kindergeldbetrag (F010) größer als 0 sein."

{
"effect": "valid",
"message": "Es müssen ein bis drei Kinder angegeben werden, jeweils mit einem Kindergeldbetrag größer als 0.",
"condition": {
"and": [
{ "greater_equal": [{ "length": { "identifier": "G001" } }, 1] },
{ "less_equal": [{ "length": { "identifier": "G001" } }, 3] },
{
"all": {
"map": {
"array": { "identifier": "G001" },
"expression": { "greater_than": [{ "identifier": "F010" }, 0] }
}
}
}
]
}
}

„Mindestens bei einem Kind (G001) muss die Schule (F011) angegeben sein."

{
"effect": "valid",
"message": "Mindestens bei einem Kind muss die Schule angegeben sein.",
"condition": {
"any": {
"map": {
"array": { "identifier": "G001" },
"expression": { "not": { "is_empty": { "identifier": "F011" } } }
}
}
}
}

„Die Anzahl der Anschriften (F002) muss der Zahl der eingetragenen Anschriften (G001) entsprechen."

{
"effect": "valid",
"message": "Die angegebene Anzahl der Anschriften muss mit den eingetragenen Anschriften übereinstimmen.",
"condition": {
"equal": [
{ "identifier": "F002" },
{ "length": { "identifier": "G001" } }
]
}
}

„Wenn mehr als eine Anschrift (G001) eingetragen ist, muss die Hauptanschrift (F001) benannt werden."

{
"effect": "require",
"target": "F001",
"message": "Bei mehreren Anschriften muss die Hauptanschrift benannt werden.",
"condition": { "greater_than": [{ "length": { "identifier": "G001" } }, 1] }
}

Datumsoperationen​

today (ohne Operanden, geschrieben als {}) liefert das aktuelle Datum. age_in_years liefert die vollen Jahre zwischen einem Datum und heute.

„Das Geburtsdatum (F004) darf nicht in der Zukunft liegen, und die Person muss volljährig sein."

{
"effect": "valid",
"message": "Das Geburtsdatum darf nicht in der Zukunft liegen und die Person muss mindestens 18 Jahre alt sein.",
"condition": {
"and": [
{ "less_equal": [{ "identifier": "F004" }, { "today": {} }] },
{ "greater_equal": [{ "age_in_years": { "identifier": "F004" } }, 18] }
]
}
}

„Ist die Person (Geburtsdatum F004) jünger als 16 Jahre, muss der gesetzliche Vertreter (F001) angegeben werden."

{
"effect": "require",
"target": "F001",
"message": "Für Personen unter 16 Jahren muss der gesetzliche Vertreter angegeben werden.",
"condition": { "less_than": [{ "age_in_years": { "identifier": "F004" } }, 16] }
}

Fachliche Prüfungen​

is_valid_iban, is_valid_bic und is_valid_email prüfen einen Text auf eine gültige IBAN, BIC bzw. E-Mail-Adresse. is_valid_date erwartet drei Ganzzahlen (Tag, Monat, Jahr) und prüft, ob sie ein gültiges Datum bilden.

„Die IBAN (F001) muss, sofern angegeben, gültig sein."

{
"effect": "valid",
"message": "Die IBAN ist ungültig.",
"condition": {
"or": [
{ "is_empty": { "identifier": "F001" } },
{ "is_valid_iban": { "identifier": "F001" } }
]
}
}

„Die E-Mail-Adresse (F006) muss gültig sein; ist sie angegeben, muss auch die BIC (F001) angegeben und gültig sein."

[
{
"effect": "valid",
"message": "Die E-Mail-Adresse ist ungültig.",
"condition": {
"or": [
{ "is_empty": { "identifier": "F006" } },
{ "is_valid_email": { "identifier": "F006" } }
]
}
},
{
"effect": "require",
"target": "F001",
"message": "Die BIC muss angegeben werden, wenn eine E-Mail-Adresse eingetragen ist.",
"condition": { "not": { "is_empty": { "identifier": "F006" } } }
},
{
"effect": "valid",
"message": "Die BIC ist ungültig.",
"condition": {
"or": [
{ "is_empty": { "identifier": "F001" } },
{ "is_valid_bic": { "identifier": "F001" } }
]
}
}
]

„Tag (F020), Monat (F021) und Jahr (F022) müssen zusammen ein gültiges Datum ergeben."

{
"effect": "valid",
"message": "Tag, Monat und Jahr ergeben kein gültiges Datum.",
"condition": {
"is_valid_date": [
{ "identifier": "F020" },
{ "identifier": "F021" },
{ "identifier": "F022" }
]
}
}

Leere Werte​

Ein optionales Element, das nicht befüllt ist, hat den Wert leer. Die Referenzlaufzeit definiert das Verhalten aller Operationen für leere Werte; andere Interpreter müssen sich identisch verhalten:

  • is_empty liefert genau dann true, wenn der Wert leer ist.
  • equal behandelt leer wie einen eigenen Wert: Ist genau ein Operand leer, ist das Ergebnis false; sind beide leer, true. not_equal ist die Negation – { "not_equal": [{ "identifier": "F003" }, "99"] } ist also auch dann true, wenn F003 leer ist.
  • Geordnete Vergleiche (less_than, greater_than, less_equal, greater_equal) liefern false, sobald ein Operand leer ist.
  • Die Zeichenkettenprädikate contains, starts_with, ends_with und matches_pattern liefern false, sobald ein Operand leer ist.
  • string_length und age_in_years reichen leer weiter: Ihr Ergebnis ist dann selbst leer, ein umgebender Vergleich damit false.
  • Bei any und all zählt ein leerer Eintrag des booleschen Arrays als false.
  • is_valid_iban, is_valid_bic und is_valid_email liefern false für leere Werte; is_valid_date liefert false, sobald einer der drei Operanden leer oder keine Ganzzahl ist.
  • Logische (and, or, xor, not) und arithmetische Operationen erwarten befüllte Operanden; dasselbe gilt für einen leeren Wert direkt an einer Stelle, die einen Wahrheitswert erfordert. Das ist ein Auswertungsfehler: Die Referenzlaufzeit verwirft dann die Auswertung des gesamten Dokuments und meldet einen allgemeinen Validierungsfehler.

Typregeln, auf die sich Konsumenten verlassen können​

  • Bedingungen von require/forbid/valid sind boolesche Ausdrücke.
  • is_empty wird nur auf optional-Kinder angewendet; eine „befüllt"-Prüfung ist { "not": { "is_empty": … } }. Ein bloßer Bezeichner wird nur dann als boolescher Wert verwendet, wenn das Kind vom Typ bool ist.
  • Felder mit Codeliste (Enum) werden gegen ihren Code als String-Literal verglichen ("98"), nie gegen die Anzeigebezeichnung.
  • Vergleiche zwischen unpassenden Typen (z. B. Text mit Zahl) kommen in gespeicherten Dokumenten nicht vor; der Typprüfer weist sie zurück.

Referenzimplementierungen​