FHIR Connect
Note
Before creating or modifying mappings in OpenFHIR, users must familiarize themselves with the FHIR Connect specification.
Understanding OpenFHIR Mappings
Importance of Proper Mapping in OpenFHIR
OpenFHIR is a powerful engine designed to process and transform healthcare data using FHIR (Fast Healthcare Interoperability Resources). However, for OpenFHIR to function correctly, it is essential that all mappings are defined according to the FHIR Connect specification. Properly structured mappings ensure interoperability, consistency, and reliable data transformation within the OpenFHIR ecosystem.
Why Adhering to FHIR Connect Specification Matters
The FHIR Connect specification establishes clear guidelines on how mappings should be structured to enable seamless data exchange. If mappings are not correctly expressed according to this specification, OpenFHIR may not operate as expected, leading to errors, incomplete transformations, or failed interoperability between systems.
By following the FHIR Connect specification:
Data transformations are predictable and reliable.
Integration between different healthcare systems remains seamless.
The engine can properly interpret and execute mappings without errors.
Engine-specific behaviour
Selecting a coding with fhirCondition
A DV_CODED_TEXT can carry more than one code: its own defining_code and any number of
TERM_MAPPINGs (_mapping:N/target in the flat format). $tofhir parses all of them into one
CodeableConcept, the element’s own code first and the mapping targets after it. $toopenehr does the
reverse, writing the first coding as the element’s code and the rest as TERM_MAPPINGs.
A fhirCondition whose targetRoot addresses those codings selects which of them cross to FHIR. In
the $toopenehr direction it filters the codings the FHIR path yields, as any condition does; in the
$tofhir direction it keeps only the codings that satisfy it. The same condition therefore reads the
same way in both directions.
The condition is coding-level when its targetRoot is
the mapped path’s
codingfor a CodeableConcept target (with.fhir: $resource.routeandtargetRoot: $resource.route.coding), orthe mapped path itself for a Coding target (
with.fhir: $resource.route.codingandtargetRoot: $resource.route.coding).
A condition anchored anywhere else (a sibling, a parent, an extension a child mapping writes) leaves the
codings alone. The operators are one of and not of; empty / not empty are presence gates
and never select.
Inside a followedBy block spell the targetRoot the way the child’s own path is spelled, relative to
the parent: a child with.fhir: route under a $resource.dosageInstruction parent takes
targetRoot: route.coding. A $resource.-anchored targetRoot is resolved against the parent’s path
there, exactly like a $resource.-anchored child path, so it would address a different element.
The typical use is a source system that sends its local code with the standard equivalent as a TERM_MAPPING, while the target profile allows exactly one coding of the standard system. The flat composition carries
{
"ordination/medication_order/order:0/route|code": "3.0000",
"ordination/medication_order/order:0/route|value": "Intravenös",
"ordination/medication_order/order:0/route|terminology": "Cytodos",
"ordination/medication_order/order:0/route/_mapping:0|match": "=",
"ordination/medication_order/order:0/route/_mapping:0/target|code": "47625008",
"ordination/medication_order/order:0/route/_mapping:0/target|terminology": "SNOMED-CT"
}
and the mapping picks the SNOMED coding:
- name: "route"
with:
fhir: "$resource.dosageInstruction.route.coding"
openehr: "$archetype/activities[at0001]/description[at0002]/items[at0091]"
fhirCondition:
targetRoot: "$resource.dosageInstruction.route.coding"
targetAttribute: "system"
operator: "one of"
criteria: "http://snomed.info/sct"
terminology:
type: "local"
conceptmap: "http://openfhir.com/ConceptMap/snomed-passthrough"
The condition is evaluated after terminology translation, so its criteria are the FHIR systems that
will actually be written. Here the "*" passthrough ConceptMap rewrites the openEHR terminology id
SNOMED-CT to http://snomed.info/sct (see Terminology); without a ConceptMap the coding keeps
the openEHR terminology id as its system, and the criteria has to name that instead.
Selection is not a gate. When no coding satisfies the condition the codings are written unchanged and a
debug line is logged — a mapping whose condition describes a value a child manual writes later (the
usual bidirectional idiom for clinicalStatus and the like) keeps working as before.
On the way back, $toopenehr sees only the codings that were written, so a many-to-one selection is
lossy: the Cytodos code above is not recovered from the SNOMED coding unless a ConceptMap maps it back.