---
{
  "title": "FHIR-Validierung: Rekursion oder keine Rekursion",
  "description": "Sollten FHIR-Profilbeschränkungen rekursiv auf verschachtelte Elemente angewendet werden? Die Spezifikation sagt ja, aber reale Profile scheitern daran. Wir haben dieses Problem beim Aufbau des Aidbox-Validators untersucht.",
  "date": "2026-03-20",
  "author": "Evgeny Mukha",
  "reading-time": "8 min read",
  "tags": ["FHIR Profiling", "FHIR Standard", "FHIR Tools", "Validation", "Conformance"]
}
---
## Wie alles begann

Während der Arbeit am [Aidbox](https://www.health-samurai.io/fhir-server) FHIR-Validator erhielten wir eine Frage von einem Kunden: Warum schlägt die Validierung bei verschachtelten `Questionnaire.item`-Elementen fehl, wenn die Einschränkung nur auf dem obersten `item` definiert ist?

Wir wendeten Profilbeschränkungen rekursiv an – wenn eine Einschränkung auf `Questionnaire.item` definiert war, erzwang unser Validator diese auch für `item.item`, `item.item.item` und so weiter. Das schien das Richtige zu sein. Schließlich heißt es in der [R5-Spezifikation](https://hl7.org/fhir/R5/profiling.html#recurse):

> Wenn ein Profil Einschränkungen für solche Elemente definiert, **gelten diese Einschränkungen auch für die rekursiven Verweise auf diese Elemente**.

Der Fall des Kunden veranlasste uns jedoch, genauer hinzusehen. Und was wir fanden, war ein echter Widerspruch in der Spezifikation.

## Der SDC-Fall

Das [SDC-Questionnaire-Profil](http://hl7.org/fhir/uv/sdc/StructureDefinition-sdc-questionnaire.html#constraints) definiert die Invariante `sdc-1` auf `Questionnaire.item`:

> Ein Element darf keine answerExpression haben, wenn bereits answerOption oder answerValueSet vorhanden ist.

Betrachten Sie diesen Questionnaire, bei dem sowohl ein Element der obersten Ebene als auch ein verschachteltes Element gegen `sdc-1` verstoßen:

```json
{
  "resourceType": "Questionnaire",
  "meta": {
    "profile": [
      "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire"
    ]
  },
  "url": "http://example.org/test",
  "status": "active",
  "item": [
    {
      "linkId": "1",
      "type": "decimal",
      "item": [
        {
          "linkId": "1.1",
          "type": "decimal",
          "answerValueSet": "http://example.org/vs",
          "extension": [
            {
              "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression",
              "valueExpression": {
                "language": "text/fhirpath",
                "expression": "1 + 1"
              }
            }
          ]
        }
      ]
    },
    {
      "linkId": "2",
      "type": "decimal",
      "answerValueSet": "http://example.org/vs",
      "extension": [
        {
          "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-answerExpression",
          "valueExpression": {
            "language": "text/fhirpath",
            "expression": "1 + 1"
          }
        }
      ]
    }
  ]
}
```

Unser Aidbox-Validator meldete Fehler bei beiden Elementen. Der HL7-Referenzvalidator auf [validator.fhir.org](https://validator.fhir.org/) meldete nur das Element der obersten Ebene. Wer hat recht?

## Analyse des Profils

Ein Blick auf die StructureDefinition des SDC-Profils macht die Antwort weniger eindeutig. Das Differential erwähnt `Questionnaire.item.item` explizit, setzt dort jedoch nur `mustSupport: true` – keine Einschränkungen, keine Invarianten:

```json
{
  "id": "Questionnaire.item.item",
  "path": "Questionnaire.item.item",
  "mustSupport": true
}
```

Ob der Profilautor beabsichtigte, dass Einschränkungen nur auf der obersten Ebene gelten, oder davon ausging, dass `sdc-1` automatisch auf verschachtelte Elemente angewendet wird, ist unklar – es ist durchaus möglich, dass er annahm, `sdc-1` würde automatisch auf verschachtelte Elemente kaskadieren. In jedem Fall schränkt das Differential `Questionnaire.item.item` nicht explizit ein, und der HL7-Validator erzwingt nur das, was das Differential vorgibt.

Aus Sicht der Spezifikation war unser Verhalten jedoch ebenfalls korrekt – Einschränkungen *sollten* rekursiv angewendet werden.

## Warum automatische Rekursion reale Profile bricht

Ich habe dies mit [Grahame Grieve](https://www.linkedin.com/in/grahame-grieve-952637/) auf [chat.fhir.org](https://chat.fhir.org/#narrow/stream/implementers/topic/Recursive%20schemas%20validation) besprochen, und seine Reaktion war unmittelbar.

Betrachten Sie das [IPS-Composition-Profil](https://build.fhir.org/ig/HL7/fhir-ips/en/StructureDefinition-Composition-uv-ips.html). Es schränkt `Composition.section` mit einer Mindest-Kardinalität von `3..*` ein. Wenn wir dies rekursiv anwenden:

- `Composition.section` – muss 3 oder mehr Abschnitte haben
- `Composition.section.section` – muss ebenfalls 3 oder mehr Abschnitte haben
- `Composition.section.section.section` – und so weiter, unendlich

Kein gültiges IPS-Dokument könnte jemals existieren. Grahames Reaktion auf den Spezifikationstext:

> *„Das ist völlig falsch, wenn es um Composition-Profile geht. Damit ist es absolut unmöglich zu arbeiten. Ich weiß nicht, was wir uns dabei gedacht haben, als wir das geschrieben haben."*

## Slicing macht es noch schlimmer

Das [Subscriptions-Backport-Profil](http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition-backport-subscription-status-r4.html) definiert Slices auf `Parameters.parameter`:

- `parameter:subscription` (erforderlich)
- `parameter:topic` (erforderlich)
- `parameter:type` (erforderlich)

Die `Parameters`-Ressource ist rekursiv – `parameter` enthält `part`, das über `contentReference` dieselbe Struktur teilt. Wenn wir Slicing rekursiv anwenden, würde jedes `.part` seine eigenen `subscription`-, `topic`- und `type`-Slices benötigen. Das ist offensichtlich nicht die Absicht der Autoren.

Diese Profile sind **weit verbreitet implementiert**. Die Erzwingung rekursiver Einschränkungen würde sie alle brechen.

## Rekursion vs. Typwiederverwendung

Die Diskussion offenbarte ein tieferliegendes Problem. FHIR verwendet `contentReference` für zwei unterschiedliche Zwecke:

**Echte Rekursion** – ein Element, das auf sich selbst verweist:
- `Questionnaire.item` -> `Questionnaire.item.item`
- `Composition.section` -> `Composition.section.section`
- `Consent.provision` -> `Consent.provision.provision`

**Typwiederverwendung** – verschiedene Elemente, die eine Struktur teilen:
- `ValueSet.compose.include` und `ValueSet.compose.exclude`
- `Parameters.parameter` und `Parameters.parameter.part`

Beide verwenden intern `contentReference`, aber die Semantik ist grundlegend verschieden. Wie [Gino Canessa](https://www.linkedin.com/in/gino-canessa/) darauf hinwies:

> *„Beide werden über den contentReference-Mechanismus realisiert, und die anfängliche Rekursion ist nicht dasselbe Element. In diesem Fall haben sie zufällig denselben Elementnamen, aber das ist nicht das, was es rekursiv macht."*

Jede Lösung muss diese Fälle unterscheiden – und weder die Spezifikation noch die aktuellen Tools tun dies.

## Das ist nicht das erste Mal

Grahame verwies auf einen [früheren Thread auf chat.fhir.org](https://chat.fhir.org/#narrow/channel/179252-IG-creation/topic/Clarification.20on.20contentReference), in dem genau dieses Problem bereits 2020 diskutiert wurde. Chris Moesel von MITRE fragte, ob Einschränkungen auf `Questionnaire.item` über `contentReference` auf `item.item` übertragen werden sollten. Die Community kam zu dem Schluss, dass dies **nicht** der Fall sein sollte – und Grahame verwies auf eine bestehende Extension, [`elementdefinition-profile-element`](http://hl7.org/fhir/StructureDefinition/elementdefinition-profile-element), als Mechanismus für explizite rekursive Wiederverwendung. Die Extension wird auf das untergeordnete Element gesetzt und verweist zurück auf das übergeordnete Profil, sodass Autoren explizit in die Vererbung von Einschränkungen einwilligen können.

Dann wurde 2023 R5 mit einem neuen Abschnitt zu [Rekursiven Elementen](https://hl7.org/fhir/R5/profiling.html#recurse) veröffentlicht, der das Gegenteil besagte: Einschränkungen **werden** standardmäßig rekursiv angewendet. Chris Moesel [machte sofort auf den Widerspruch aufmerksam](https://chat.fhir.org/#narrow/channel/179252-IG-creation/topic/Clarification.20on.20contentReference/near/350340728). Wie Grahame es formulierte: *„Ich weiß nicht, was wir uns dabei gedacht haben, als wir das geschrieben haben."*

Die Community hatte das Problem also bereits identifiziert, eine Extension zur Lösung entwickelt – und dann ging die Spezifikation in die entgegengesetzte Richtung.

## Ein möglicher Lösungsansatz: eine Extension auf ElementDefinition

Im Laufe der Diskussion schlug ich eine Lösung vor: eine Extension, die explizit steuert, ob Einschränkungen rekursiv vererbt werden. Die Idee ist einfach – ein Flag auf `ElementDefinition`, das Validatoren mitteilt: „Wende Einschränkungen des übergeordneten Elements auf diesen rekursiven Verweis an (oder nicht)."

Gino Canessa entwickelte dies weiter zu einem flexibleren Ansatz: eine Extension auf dem *untergeordneten* Element, die auf das Element verweist, von dem es Einschränkungen erben soll. Beispielsweise könnte `Questionnaire.item.item` explizit angeben: „Übernimm Einschränkungen von `Questionnaire.item`":

```
Questionnaire.item          – Einschränkungen hier definiert
Questionnaire.item.item     – Extension: "inherit-constraints-from: Questionnaire.item"
```

Dieser Ansatz löst beide Fälle:

- **Echte Rekursion** (`Questionnaire.item.item`): Der Profilautor fügt die Extension hinzu, wenn er möchte, dass Einschränkungen kaskadieren – Opt-in
- **Typwiederverwendung** (`ValueSet.compose.include` / `.exclude`): Jedes Element bleibt standardmäßig unabhängig – keine versehentliche Übertragung von Einschränkungen

Die zentrale Designfrage ist der Standard. Die Community tendiert zu **nicht-rekursiv als Standard** mit explizitem Opt-in:

| Position | Befürworter | Begründung |
|----------|-------------|------------|
| **Nicht-rekursiv als Standard**, Opt-in über Extension | Gino Canessa, [Grahame Grieve](/articles/grahame-grieve-interview-future-of-fhir-in-2025) | Sicherste Option für bestehende Profile; vermeidet Breaking Changes |
| **Rekursiv als Standard**, Opt-out über Extension | Brian Postlethwaite | Intuitiver für gängige Anwendungsfälle |
| **Bevorzugt rekursiv**, akzeptiert nicht-rekursiv | Lloyd McKenzie | Eine Änderung des Standards wäre ein Breaking Change |

Lloyd McKenzie fasste die Spannung treffend zusammen:

> *„Es muss eine Möglichkeit geben, Einschränkungen zu definieren, die rekursiv gelten, denn das ist definitiv ein benötigter Anwendungsfall. Da das aktuelle Verhalten jedoch nicht so ist, könnte eine Änderung des Standards einen Breaking Change darstellen."*

## Was wir dagegen unternehmen

In [FHIR Schema](https://github.com/fhir-schema/fhir-schema) – dem baumförmigen Validierungsformat, das wir bei Health Samurai entwickeln – tritt dieses Problem als explizite architektonische Entscheidung auf. Wenn wir StructureDefinitions in einen Schema-Baum transpilieren, wird `contentReference` zu einem Zeiger auf einen anderen Knoten, und wir müssen entscheiden: Die Einschränkungen des übergeordneten Elements kopieren oder nicht?

Vorerst haben wir den [Aidbox-Validator](https://www.health-samurai.io/fhir-server) am HL7-Referenzvalidator ausgerichtet – Einschränkungen werden **nicht** rekursiv angewendet, es sei denn, das Profil definiert sie explizit auf verschachtelten Elementen. Das entspricht der Art und Weise, wie Profile in der Praxis tatsächlich geschrieben werden.

Das Thema ist für die Diskussion beim HL7 Working Group Meeting in Rotterdam vorgemerkt. Wir erwarten, dass dort konkrete Vorschläge für einen Extension-Mechanismus und eine klarere Spezifikationssprache erarbeitet werden.

## Was das für Implementierer bedeutet

Wenn Sie mit rekursiven Elementen arbeiten (`Questionnaire.item`, `Composition.section`, `Consent.provision`, `Parameters.parameter`):

- **Aktuelles Verhalten verschiedener Validatoren**: Einschränkungen werden nicht rekursiv angewendet, unabhängig davon, was die R5-Spezifikation besagt
- **Wenn Sie Einschränkungen auf allen Verschachtelungsebenen benötigen**: Definieren Sie diese explizit im Differential Ihres Profils für jede Ebene, oder verwenden Sie [FHIRPath](/articles/unlocking-fhirpath-power-a-deep-dive-into-static-type-analysis-for-robust-tooling)-Invarianten, die den Baum traversieren
- **Wenn Sie einen Validator entwickeln**: Wenden Sie Einschränkungen nicht standardmäßig rekursiv an – das wird weit verbreitete Profile brechen

Dies ist eine Lücke in der Spezifikation, kein Fehler. Die Spezifikation sagt eine Sache, reale Profile benötigen eine andere, und Validatoren haben pragmatisch das Verhalten gewählt, das bestehende Implementierungen nicht bricht.

## Nächster Schritt: WGM Rotterdam

Wir planen, dieses Thema beim [HL7 Working Group Meeting in Rotterdam](https://www.hl7europe.org/2026-may-hl7-fhir-connectathon-and-working-group-meeting/) mit einem konkreten Vorschlag für den oben beschriebenen Extension-Mechanismus einzubringen. Das Ziel ist es, eine Einigung mit der FHIR Infrastructure Working Group zu erzielen und dies in eine formelle Spezifikationsänderung zu überführen.

Wenn Sie dieses Problem in Ihren Profilen oder Ihrem Validator bereits erlebt haben – wir würden Ihre Anwendungsfälle gerne vor dem Meeting hören. Beteiligen Sie sich an der [Diskussion auf chat.fhir.org](https://chat.fhir.org/#narrow/stream/implementers/topic/Recursive%20schemas%20validation) oder wenden Sie sich direkt an uns.

Siehe auch: [So erstellen Sie einen FHIR Implementation Guide](/blog/how-to-create-a-fhir-implementation-guide) und [FHIR Additional Bindings](/blog/fhir-additional-bindings).