POC - Mapping CDA to FHIR
0.1.0 - ci-build

POC - Mapping CDA to FHIR - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

## Accueil

Official URL: https://interop.esante.gouv.fr/ig/fhir/mappingcdafhir/ImplementationGuide/ans.fhir.fr.mappingcdafhir | Version: 0.1.0
Draft as of 2025-11-07 | Computable Name: CDA2FHIRMAP

FHIR Mapping Language for CDA to FHIR transformation
Proof of concept for CDA to FHIR transformation

> Cet Implementation Guide n'est pas la version courante, il s'agit de la version en intégration continue soumise à des changements fréquents uniquement destinée à suivre les travaux en cours. La version courante sera accessible via l'URL canonique suite à la première release : http://interop.esante.gouv.fr/ig/fhir/[code - ig]

### Introduction

Dans le cadre de l'Espace Européen des Données de Santé, l'ANS a entrepris des travaux pour anticiper la transition CDA vers FHIR dans le cadre des 5 cas d'usages priorisés par l'Europe : le compte rendu de biologie, la ePrescription et eDispensiation, le compte rendu d'hospitalisation, le résumé patient et le compte rendu d'imagerie.

Les travaux de l'ANS se distinguent en deux parties :

- créer les spécifications françaises en FHIR qui reprend l'historique CDA tout en s'alignant avec les contraintes européennes (cf. https://github.com/ansforge/IG-document-core)
- tester le FHIR Mapping Language, outil permettant la transformation des documents CDA vers FHIR.

### Guide de démarrage rapide (Quick Start)

Ce guide vous permet de tester rapidement la transformation de documents CDA vers FHIR en utilisant matchbox et les exemples fournis.

#### Prérequis

- Docker installé sur votre machine
- Un client REST (ex: VS Code avec l'extension REST Client, IntelliJ IDEA, ou curl)
- Accès au repository IG-mapping-cda-fhir

#### Étape 1 : Télécharger l'image Docker matchbox

    docker pull europe-west6-docker.pkg.dev/ahdis-ch/ahdis/matchbox:v4.0.12

#### Étape 2 : Lancer le conteneur Docker

Important : Adaptez le chemin selon votre installation locale. Le chemin doit pointer vers le dossier `input/with-all` de votre projet.

    docker run -d --name matchbox -p 8080:8080 \
      -v /chemin/absolu/vers/IG-mapping-cda-fhir/input/with-all:/config \
      europe-west6-docker.pkg.dev/ahdis-ch/ahdis/matchbox:v4.0.12

Ou utilisez le script de démarrage automatique :

    ./start-matchbox.sh

#### Étape 3 : Vérifier le démarrage

Pour suivre les logs de matchbox :

    docker logs --follow matchbox

Attendez que matchbox ait terminé son démarrage. L'interface sera accessible sur : `http://localhost:8080/matchbox`

#### Étape 4 : Charger les ConceptMaps

Certains StructureMaps utilisent des ConceptMaps externes pour la traduction de codes terminologiques. Il faut les charger avant les StructureMaps.

    # Charger le ConceptMap pour le genre (administrative-gender)
    curl -X POST http://localhost:8080/matchbox/fhir/ConceptMap \
      -H "Content-Type: application/fhir+json" \
      --data-binary @input/resources/ConceptMap-cm-v3-administrative-gender.json

#### Étape 5 : Charger les StructureMaps et lancer les transformations

Les fichiers HTTP de test se trouvent dans le dossier `http-test/`. Utilisez le fichier `fr_cdatofhir_mde.http` avec votre client REST.

Avec VS Code et l'extension REST Client :

1. Ouvrez le fichier `http-test/fr_cdatofhir_mde.http`
2. Exécutez séquentiellement les requêtes HTTP dans l'ordre suivant :
   - Requête 0 : Charger ConceptMap-cm-v3-administrative-gender.json
   - Requête 1 : Charger CDAtoFHIRTypes.fml
   - Requête 2 : Charger CdaToBundle.fml
   - Requête 3 : Charger CDAFrToBundle.fml
   - Requête 4 : Charger CDAFrMDEToBundle.fml
   - Requête 5 : Transformer CSE-MDE_2023.01.xml (sortie JSON)
3. Cliquez sur "Send Request" au-dessus de chaque requête

Avec curl (exemple complet) :

    # 1. Charger les ConceptMaps nécessaires
    curl -X POST http://localhost:8080/matchbox/fhir/ConceptMap \
      -H "Content-Type: application/fhir+json" \
      --data-binary @input/resources/ConceptMap-cm-v3-administrative-gender.json

    # 2. Charger les StructureMaps dans l'ordre
    curl -X POST http://localhost:8080/matchbox/fhir/StructureMap \
      -H "Accept: application/fhir+xml;fhirVersion=4.0" \
      -H "Content-Type: text/fhir-mapping" \
      --data-binary @input/fml/CDAtoFHIRTypes.fml

    curl -X POST http://localhost:8080/matchbox/fhir/StructureMap \
      -H "Accept: application/fhir+xml;fhirVersion=4.0" \
      -H "Content-Type: text/fhir-mapping" \
      --data-binary @input/fml/CdaToBundle.fml

    curl -X POST http://localhost:8080/matchbox/fhir/StructureMap \
      -H "Accept: application/fhir+xml;fhirVersion=4.0" \
      -H "Content-Type: text/fhir-mapping" \
      --data-binary @input/fml/CDAFrToBundle.fml

    curl -X POST http://localhost:8080/matchbox/fhir/StructureMap \
      -H "Accept: application/fhir+xml;fhirVersion=4.0" \
      -H "Content-Type: text/fhir-mapping" \
      --data-binary @input/fml/CDAFrMDEToBundle.fml

    # 3. Transformer un document CDA
    curl -X POST "http://localhost:8080/matchbox/fhir/StructureMap/\$transform?source=https://interop.esante.gouv.fr/ig/fhir/mappingcdafhir/StructureMap/CdaFrMDEToBundle" \
      -H "Accept: application/fhir+json;fhirVersion=4.0" \
      -H "Content-Type: application/fhir+xml;fhirVersion=4.0" \
      --data-binary @input/attachments/CSE-MDE_2023.01.xml

#### Exemple CDA disponible

Le dossier `input/attachments/` contient un exemple de document CDA français :

- CSE-MDE_2023.01.xml : Carnet de santé de l'enfant - Mesures (3 observations : Poids, Taille, Périmètre crânien)

#### Résultat attendu

Si la transformation réussit, vous obtiendrez un Bundle FHIR contenant les ressources converties depuis le document CDA.

Note importante : Il peut y avoir des erreurs dans les fichiers FML lors de la transformation. L'objectif de ce POC est de valider le processus de transformation. Les erreurs dans les mappings seront traitées ultérieurement.

### Résultats des transformations

Les transformations CDA-FHIR ont été exécutées avec les résultats suivants :

#### Transformation réussie

Fichier source | StructureMap utilisé | Fichier résultat | Ressources FHIR | Observations | Statut
--- | --- | --- | --- | --- | ---
CSE-MDE_2023.01.xml | CdaFrMDEToBundle | Bundle-fe569e1f-32d4-4ba4-b5ad-88082bf5470a.json | 11 | 3 | ✅ Succès complet

Détails de la transformation :

Document CSE-MDE (Carnet de Santé de l'Enfant - Mesures) :

- StructureMap utilisé : `CdaFrMDEToBundle` - Mapping spécifique pour le contexte français
- Imports : Utilise `CdaToFHIRTypes`, `CdaToBundle` et `CdaFrToBundle`
- Ressources générées (11 au total) :
  - 1 Composition (métadonnées du document)
  - 1 Patient (avec identifiant INS-NIR, nom, genre, date de naissance)
  - 1 Encounter (contexte de la rencontre)
  - 1 Location (lieu de la consultation)
  - 2 Practitioner (praticiens impliqués)
  - 2 Organization (organisations de santé)
  - 3 Observations :
    - Poids (29463-7) = 3900 g
    - Taille (8302-2) = 52 cm
    - Périmètre crânien (8287-5) = 35 cm

### Architecture du mapping CdaFrMDEToBundle

Le mapping `CdaFrMDEToBundle.fml` est un mapping spécialisé pour les documents CSE-MDE français qui combine :

Architecture du mapping :

- Imports : Utilise les mappings de base (`CdaToFHIRTypes`, `CdaToBundle`, `CdaFrToBundle`)
- Réutilisation : Exploite les fonctions existantes pour Patient, Composition, Encounter, Location, etc.
- Navigation personnalisée : Implémente une navigation spécifique pour extraire les observations imbriquées dans les organizers
- Traitement complet : Gère toutes les ressources nécessaires pour un document CSE-MDE

Résultats obtenus :

- ✅ Génération du Bundle FHIR avec structure document complète
- ✅ Transformation du Patient avec identifiant INS-NIR, nom, genre, date de naissance
- ✅ Création de la Composition avec métadonnées et sections
- ✅ Génération automatique des ressources contextuelles (Encounter, Location, Practitioner, Organization)
- ✅ Extraction des Observations depuis `organizer > component > observation`
- ✅ Transformation des codes LOINC et valeurs quantitatives avec unités

Exemple d'Observation générée :

    {
      "resourceType": "Observation",
      "status": "final",
      "category": [{
        "coding": [{
          "system": "http://terminology.hl7.org/CodeSystem/observation-category",
          "code": "vital-signs"
        }]
      }],
      "code": {
        "coding": [{
          "system": "http://loinc.org",
          "code": "29463-7",
          "display": "Poids"
        }]
      },
      "subject": {
        "reference": "urn:uuid:..."
      },
      "effectiveDateTime": "2023-01-06",
      "valueQuantity": {
        "value": 3900,
        "unit": "g",
        "system": "http://unitsofmeasure.org",
        "code": "g"
      }
    }

Améliorations récentes apportées au mapping :

- ✅ Ajout de `Observation.category` : Toutes les observations sont catégorisées comme `vital-signs` conformément au package ANS ans.fhir.fr.mesures#3.1.0
- ✅ Ajout de `Observation.effectiveDateTime` : Extrait depuis `effectiveTime` de l'observation CDA (si présent et non `nullFlavor`)
- ✅ Correction de `Observation.status` : Mapping de CDA "completed" vers FHIR "final"
- ✅ Ajout du système UCUM aux quantités : Toutes les `valueQuantity` incluent `system: "http://unitsofmeasure.org"` et `code` en plus de `unit`
- ✅ Conversion des codes LOINC : Système correctement mappé vers `http://loinc.org`
- ✅ Ajout de `Encounter.status` : Défini à `finished` pour les rencontres terminées
- ✅ Ajout de `Encounter.class` : Extrait du code CDA de la rencontre
- ✅ Correction de `Patient.birthDate` : Format date simple conforme FHIR
- ✅ Correction de `Composition.confidentiality` : Code simple au lieu d'objet complexe
- ✅ Correction de `attester.time` : Format dateTime conforme FHIR
- ✅ Ajout de `meta.profile` : Profils ANS ajoutés selon le code LOINC (mesures-fr-observation-body-weight, mesures-fr-observation-bodyheight, mesures-observation-head-circumference)

Limitations identifiées dans les données CDA source :

Les exemples CDA fournis présentent certaines limitations qui génèrent des warnings FHIR (non bloquants) :

1. ⚠️ Absence de timezone sur `Encounter.period` : Les dates/heures de la rencontre dans le CDA n'incluent pas de timezone

       <!-- CDA source -->
       <effectiveTime>
         <low value="20250106111510"/>  <!-- Pas de timezone +0100 -->
         <high value="20250106113623"/> <!-- Pas de timezone +0100 -->
       </effectiveTime>

   Impact : Warning FHIR "If a date has a time, it must have a timezone"

   Solution : Ajouter le timezone dans le CDA source (ex: `20250106111510+0100`)

2. ⚠️ Absence de `Observation.effectiveDateTime` : Les observations CDA utilisent `nullFlavor="NASK"` (Not Asked)

       <!-- CDA source -->
       <observation>
         <code code="29463-7" displayName="Poids" codeSystem="2.16.840.1.113883.6.1"/>
         <effectiveTime nullFlavor="NASK"/>  <!-- Pas de date effective -->
         <value xsi:type="PQ" value="3900" unit="g"/>
       </observation>

   Impact : Warning FHIR "Best Practice Recommendation: In general, all observations should have an effective[x]"

   Solution : Fournir une date/heure effective dans le CDA source (ex: `<effectiveTime value="20230106"/>`)

Note : Ces limitations proviennent des données CDA d'exemple et non du mapping FML. Le mapping transforme fidèlement les données CDA disponibles.

### Difficultés identifiées dans le mapping automatique CDA-FHIR

Le processus de transformation automatique CDA vers FHIR présente certaines difficultés inhérentes aux différences de modélisation entre les deux standards :

#### 1. Ambiguïté sémantique des structures CDA

Problème identifié : `healthCareFacility` et `serviceProviderOrganization`

Dans le CDA, la structure `componentOf > encompassingEncounter > location > healthCareFacility` contient :

- Un `code` décrivant le type d'établissement (ex: SA05 "Centre de santé" du TRE_R02-SecteurActivite)
- Une `location` (lieu physique avec adresse)
- Optionnellement un `serviceProviderOrganization` (organisation gestionnaire)

Difficulté de mapping :

Le code SA05 du `healthCareFacility` devrait logiquement être mappé vers :

1. ✅ `Location.type` - pour indiquer le type de lieu physique
2. ❓ `Organization.type:secteurActiviteRASS` - pour indiquer le secteur d'activité de l'organisation

Cependant, il existe une ambiguïté sémantique :

- Le `serviceProviderOrganization` dans le CDA peut représenter :
  - L'organisation qui opère directement le centre de santé (dans ce cas, SA05 s'applique bien)
  - Une organisation parente ou gestionnaire différente (dans ce cas, SA05 pourrait ne pas s'appliquer)

Impact :

- Un mapping automatique qui copie systématiquement le code du `healthCareFacility` vers l'`Organization` peut introduire des incohérences sémantiques
- Il n'existe pas de règle universelle dans le CDA pour distinguer ces deux cas
- Cette ambiguïté nécessite souvent une analyse contextuelle manuelle ou des règles métier spécifiques au projet

Solutions possibles :

1. Mapping conservateur : Ne mapper que vers `Location.type` (approche actuelle)
2. Mapping avec hypothèse : Copier vers `Organization.type` en documentant l'hypothèse que le `serviceProviderOrganization` est l'établissement lui-même
3. Mapping conditionnel : Définir des règles métier basées sur le contexte du document (type de document, type d'établissement, etc.)

Cette difficulté illustre que le mapping CDA-FHIR n'est pas toujours une transformation mécanique 1:1, mais nécessite parfois des choix d'implémentation basés sur la compréhension du contexte métier.

### Arrêter et redémarrer

Pour arrêter le conteneur :

    docker stop matchbox

Pour redémarrer :

    docker start matchbox

Pour supprimer le conteneur (et repartir de zéro) :

    docker rm -f matchbox

### Configuration avancée

Le fichier `input/with-all/application.yaml` configure matchbox avec :

- Les packages FHIR de base (R4 core, terminologies, extensions)
- Le package CDA (hl7.cda.uv.core)
- Le package ANS FHIR EDS

Pour modifier la configuration, éditez `application.yaml` puis supprimez et recréez le conteneur Docker.

### Auteurs et contributeurs

Role | Nom | Organisation | Contact
--- | --- | --- | ---
Primary Editor | Prenom Nom | Agence du Numérique en Santé | prenom.nom@address.email

Merci à Oliver Egger (Ahdis, HL7 Suisse) qui a travaillé sur la première brique sur laquelle repose ces travaux et sur l'outil matchbox permettant d'effectuer la transformation.

https://github.com/hl7ch/cda-fhir-maps

### Dépendances

IG | Package | FHIR | Comment
--- | --- | --- | ---
POC - Mapping CDA to FHIR | ans.fhir.fr.mappingcdafhir#0.1.0 | R4 |
HL7 Terminology (THO) | hl7.terminology.r4#6.5.0 | R4 | Automatically added as a dependency - all IGs depend on HL7 Terminology
FHIR Extensions Pack | hl7.fhir.uv.extensions.r4#5.2.0 | R4 |
Clinical Document Architecture | hl7.cda.uv.core#2.0.0-sd | R5 |
FHIR Extensions Pack | hl7.fhir.uv.extensions.r5#5.1.0 | R5 |
HL7 Terminology (THO) | hl7.terminology#5.2.0 | R4 |
FHIR Extensions Pack | hl7.fhir.uv.extensions.r4#1.0.0 | R4 |
Annuaire Santé | ans.fhir.fr.annuaire#1.1.0 | R4 |
Guide d'implémentation Fr Core | hl7.fhir.fr.core#2.1.0 | R4 |
HL7 Terminology (THO) | hl7.terminology.r4#6.0.2 | R4 |
Nomenclatures des objets de santé (NOS) | ans.fr.nos#1.3.0 | R4 |
Nomenclatures des objets de santé (NOS) | ans.fr.nos#1.5.0 | R4 |
HL7 Terminology (THO) | hl7.terminology.r4#6.2.0 | R4 |
HL7 Terminology (THO) | hl7.terminology.r4#5.5.0 | R4 |
hl7.fhir.fr.core | hl7.fhir.fr.core#1.1.0 | R4 |
FHIR Tooling Extensions IG | hl7.fhir.uv.tools.r4#0.8.0 | R4 | for example references

Package hl7.fhir.uv.extensions.r4#5.2.0 This IG defines the global extensions - the ones defined for everyone. These extensions are always in scope wherever FHIR is being used (built Mon, Feb 10, 2025 21:45+1100+11:00)

Package hl7.fhir.uv.extensions.r5#5.1.0 This IG defines the global extensions - the ones defined for everyone. These extensions are always in scope wherever FHIR is being used (built Sat, Apr 27, 2024 18:39+1000+10:00)

Package hl7.fhir.uv.extensions.r4#1.0.0 This IG defines the global extensions - the ones defined for everyone. These extensions are always in scope wherever FHIR is being used (built Sun, Mar 26, 2023 08:46+1100+11:00)

Package ans.fr.nos#1.3.0 Les nomenclatures des objets de Sante (built Thu, Aug 29, 2024 14:54+0000+00:00)

Package ans.fr.nos#1.5.0 Les nomenclatures des objets de Sante (built Tue, Feb 11, 2025 10:50+0000+00:00)

Package ans.fhir.fr.annuaire#1.1.0 Ressources de conformité basées sur le modèle d'exposition de l'Annuaire Santé. (built Mon, Apr 14, 2025 13:04+0000+00:00)

Package hl7.fhir.fr.core#1.1.0 The FR Core Implementation Guide is based on FHIR Version R4 and defines the minimum set of constraints on the FHIR resources to create the FR Core Profiles. It also defines the minimum set of FHIR RESTful interactions for each of the FR Core Profiles to access patient data. By establishing the “floor” of standards to promote interoperability and adoption through common implementation, it allows for further standards development evolution for specific uses cases.

Package hl7.fhir.uv.tools.r4#0.8.0 This IG defines the extensions that the tools use internally. Some of these extensions are content that are being evaluated for elevation into the main spec, and others are tooling concerns (built Tue, Aug 5, 2025 20:09+1000+10:00)

### Propriété intellectuelle

Certaines ressources sémantiques de ce guide sont protégées par des droits de propriété intellectuelle couverte par les déclarations ci-dessous. L’utilisation de ces ressources est soumise à l’acceptation et au respect des conditions précisées dans la licence d’utilisation de chacune d’entre elle.

- ISO maintains the copyright on the country codes, and controls its use carefully. For further details see the ISO 3166 web page: https://www.iso.org/iso-3166-country-codes.html
  Show Usage
  - ISO 3166-1 Codes for the representation of names of countries and their subdivisions — Part 1: Country code: CDA2FHIRMAP, CdaFrMDEToBundle... Show 6 more, CdaFrToBundle, CdaToBundle, CdaToFHIRTypes, CdaToFhirAdministrativeGender, ConceptMapOidSpecialiteOrdinale and OID2URIConceptMapANS
- The UCUM codes, UCUM table (regardless of format), and UCUM Specification are copyright 1999-2009, Regenstrief Institute, Inc. and the Unified Codes for Units of Measures (UCUM) Organization. All rights reserved. https://ucum.org/trac/wiki/TermsOfUse
  Show Usage
  - Unified Code for Units of Measure (UCUM): Bundle/fe569e1f-32d4-4ba4-b5ad-88082bf5470a
- This material derives from the HL7 Terminology (THO). THO is copyright ©1989+ Health Level Seven International and is made available under the CC0 designation. For more licensing information see: https://terminology.hl7.org/license.html
  Show Usage
  - Observation Category Codes: Bundle/fe569e1f-32d4-4ba4-b5ad-88082bf5470a
  - identifierType: Bundle/fe569e1f-32d4-4ba4-b5ad-88082bf5470a
  - ActCode: Bundle/fe569e1f-32d4-4ba4-b5ad-88082bf5470a