FHIR mapping language


Introduction


In this module you will learn how FHIR supports mapping and how you can use the FHIR mapping language.

The topics covered in this module are:

  • Introduction to mapping facilities in FHIR and their differences
  • The ConceptMap resource
  • Free text mapping within profiles
  • The FHIR mapping language
  • The StructureMap resource

Reading material


1. Differences between the mapping facilities in FHIR

FHIR has, over time, acquired different mapping-related features to deal with various use-cases:

Here's a rough breakdown of them:

Concept Use this to create
ConceptMap mappings between codes in different ValueSets
mapping field in every element traceability from FHIR elements to other standards
FHIR Mapping language transformations from one data format to another
StructureMap FHIR Mapping language transformations in resource form

1.1 ConceptMap

The ConceptMap resource defines a mapping from a set of codes (concepts) defined in a ValueSet to one or more codes defined in other ValueSets. For example, say you want to create a mapping of LOINC® codes to their equivalent SNOMED® codes - you'd use a ConceptMap for this. You could then publish your ConceptMap in an Implementation Guide (IG), use it for machine translation or codes, or include it in your FHIR mapping language transformation - see 1.2 below.

1.2 Mapping field in every element

You might notice this field in Forge:

This comes from ElementDefinition.mapping, which is a free-text field that you use to create traceability to other standards within your FHIR profiles. For example, when you're mapping a national standard for prescriptions to FHIR, you'd mention the equivalent element(s) from the national standard in your mapping field. This field is thus not related to the ConceptMap resource.

1.3 FHIR Mapping language

Data mapping is the process of defining how data from one data model maps to another data model, and the FHIR Mapping language is a transformation language to address that need (e.g. the conversion of HL7 version 2 or CDA to FHIR). Different technologies already exist to transform data from one data model to another - such as 3GL, XSLT - but given FHIR's unique position (open standard with XML and JSON support), none of the existing technology satisfied the requirements. To use the FHIR mapping language, you need at minimum to create a transformation map which will instruct the mapping engine on how to convert the elements in an instance of data from one model to another. That transformation map can make use of embedded ConceptMaps to transform codes within the data elements from one code to another.

The FHIR mapping language is not related to the mapping field that's present in the profiles, as that is a free-text field you can use to provide traceability in your profiles.

1.4 StructureMap

A FHIR Mapping language transformation map can exist in two forms - as a declarative program ("concrete syntax") or as a StructureMap resource ("abstract syntax"). The StructureMap resource is thus just a resource form representation of a FHIR Mapping language transformation map.

2. Overview of the mapping facilities in FHIR

2.1 ConceptMap

You can use the ConceptMap resource to define mappings between codes from different ValueSets. Use the source element to define the source of the concepts that you want to map. The target element provides the target you want to map the concepts to. The group element contains a list of concepts and the target concept(s) these should be mapped to. Below is an example from the mapping of the concept 'home' between HL7 version 3 and FHIR. In HL7 version 3 the code of this concept is 'H', while in FHIR the code of this concept is 'home'. In the XML code below you can see that the source concept 'home' is mapped to the target concept 'H' (both having the same display value).

 <sourceUri value="http://hl7.org/fhir/ValueSet/address-use"/> 
  <targetUri value="http://hl7.org/fhir/ValueSet/v3-AddressUse"/> 
  <group> 
    <source value="http://hl7.org/fhir/address-use"/> 
    <target value="http://hl7.org/fhir/v3/AddressUse"/> 
    <element> 
      <code value="home"/> 
      <display value="home"/> 
      <target> 
        <code value="H"/> 
        <display value="home"/> 
      </target> 
    </element> 

2.2 Mapping field in every element

The ElementDefinition.mapping element allows you to define a free text mapping for this element within your profile. This mapping is however harder to use when reusing profiles.

The mapping.identity element refers to the mapping system that is used (the mapping systems should also be defined at a higher level in the StructureDefinition.mapping element). The mapping.map element defines the value that is mapped to the parent element. For example, the code below shows a mapping from the field PasientID to the element Procedure.subject.

<element id="Procedure.subject">
...
<mapping>
  <identity value="helsevest">
  <map value="PasientID"/>
</mapping>

The Procedure profile contains a definition of the mapping system in the mapping element. The identity of the mapping system in this example is helsevest.

<mapping>
  <identity value="helsevest" />
  <name value="HV Architecture Document" />
</mapping>

In the core specification you find mappings from HL7 v3 RIM, LOINC, CDA and HL7 v2 to core FHIR resources (go to the Mappings tab of a resource, e.g. https://hl7.org/fhir/patient-mappings.html).

2.3 FHIR Mapping language

The FHIR mapping language is purely declarative - this means that instead of giving concrete instructions on how to process data, you instead describe how the processed data should look like, and the engine figures out how to transform it. The FHIR mapping language addresses two very different kinds of transformations:

  • Structural changes between the source and target structures (skeletal mapping). This covers renaming data elements, merging elements, or creating new ones.
  • Differences in content and formats in string (and related) primitives contained within the structures (conceptual mapping). This covers data within the elements: trimming text, capitalizing text, and so on.

FHIR Mapping language transformation maps are also uni-directional: they map from the source structure to the target structure, and no reverse map is implied. Even if the reserve mapping is simple, and happens to run losslessly, it cannot be assumed that it is correct - there might be conditions on the reverse transformation would not have been applied.

2.3.1 FHIR Mapping Language transformation maps

The FHIR mapping language can be applied to any content that is a directed acyclic graph with metadata (DAG-M). A directed acyclic graph (DAG) is a graph that flows in one direction and no element can be a child of itself (there are no cycles). A DAG-M is a DAG with metadata (for example each element has a name, type and cardinality). The FHIR mapping language describes how one (set of) DAG-M(s) (an instance) are transformed to another (set of) DAG-M(s). The instances can be strongly typed (specifically when they have formal definitions represented as StructureDefinitions), but this is not required.

A Map has 6 parts:

  • Metadata
  • Embedded ConceptMaps to translate between different code systems (optional)
  • References to the structures involved in the mapping (optional)
  • Imports: additional Maps used by this map (optional)
  • A series of groups, each with a list of input variables
  • A series of transformation rules in each group

4.2 Metadata

The first part of the map contains a unique canonical URL to identify the map and a human readable name of the map. The syntax is as follows:

map "[url]" = "[name]"

Here below is an example of a map named exampleMap:

map "https://hl7.org/fhir/StructureMap/exampleMap" = exampleMap

2.3.2 Embedded ConceptMaps

You can (optionally) define a ConceptMap and embed it in your code. Note the differences with importing existing Maps as explained in paragraph 3.4

The syntax is as follows:

conceptmap "[name]" {

  prefix [x] = "[url]"
  prefix [y] = "[url]"

  x:[sourcevalue] = y:[targetvalue]
  x:[sourcevalue] = y:[targetvalue]
}

For example, let's define a ConceptMap called myConceptMap that maps FHIR codes for address use to HL7 version 3 codes for address use. In this example, the FHIR value 'home' is begin mapped to the HL7 version 3 value 'H'.

conceptmap myConceptMap {

  prefix s = "http://hl7.org/fhir/ValueSet/address-use"
  prefix t = "http://hl7.org/fhir/ValueSet/v3-AddressUse"

  s:home = t:H
}

2.3.3 References to structures

The next (optional) part of the map is a list of one or more StructureDefinitions that are used in the map and the way in which they are used (either as a source, target, queried or produced). The syntax is as follows:

uses "[url]" (alias name) as [mode]

For example, if you would like to list your own Patient profile (which you called myPatient) as a source and another Patient profile (suppose this one is called otherPatient) as a target, the required code would be as follows:

uses "https://hl7.org/fhir/StructureDefinition/myPatient" as source
uses "https://hl7.org/fhir/StructureDefinition/otherPatient" as target

You may choose to add an alias as well for these StructureDefinitions, so you can use these in the code later on, but it is not mandatory to do so.

2.3.4 Import maps

The next (optional) part of the map is a list of additional maps that are used in this map. The syntax is as follows:

imports "[url]"

Below is an example of the import of a StructureMap called mapA and a ConceptMap called mapB.

imports "https://hl7.org/fhir/StructureMap/mapA"
imports "https://hl7.org/fhir/ConceptMap/mapB"

2.3.5 Groups

Each map should have at least one group of transform rules. A group is a set of related rules that share the same input and output variables defining exactly which instances are passed to mapping and by which name. The syntax is as follows:

group (for type) [group-name] (extends [other-group])
  input [name] : [type] as [mode]
  //rules go here
endgroup

For example, we can define a group called exampleGroup with input variable A and output variable B. We will show an example of how to define the rules in the next section.

group exampleGroup
  input "source" : A as source
  input "target" : B as target

//rules go here

endgroup

The for type indicates if an instance should be mapped to a specified target data type.

2.3.6 Transform rules

Transform rules describe how source content is transformed into target content. Each rule has four main sections:

  • Name - The identity of the rule (for example for logging/debugging)
  • Source Content - One or more elements from the source that contribute to the mapping
  • Target Transform - One or more specifications of the content to create in the target model
  • Dependent Rules - Specifies which (if any) rules or groups to apply within the scope of the rule

The syntax for defining transform rules is as follows:

name_of_rule: for src_context.field as new_variable where condition make tgt_context.field as new_variable = create([type]) then [details]

For example, let's say you want to keep identifier the same and copy its value from source to target without transformation. The syntax would be as follows:

"rule_1_copy_identifier" : for source.identifier as a make target.identifier = a

Let's say for maritalStatus, you have added the following category in myPatient: O = Other, but the otherPatient profile does not allow for other categories than the ones defined in the marital-status ValueSet. You need to map your category to one of the categories from the marital-status ValueSet. Although there is no mapping available that has the exact same meaning, you choose to map this category to the category UNK = Unknown. The syntax would be as follows:

"rule_2_transform_gender" : for source.maritalstatus as m where m="O" make target.maritalStatus = "UNK"

Your group is now composed of one rule that copies the value of identifier and one rule that transforms the value of maritalStatus:

group exampleGroup
  input "source" : A as source
  input "target" : B as target

"rule_1_copy_identifier" : for source.identifier as a make target.identifier = a
"rule_2_transform_gender" : for source.maritalstatus as m where m="O" make target.maritalStatus = "UNK"

endgroup

2.3.7 Learn more

To learn more about the FHIR Mapping Language, have a look at the HL7 FHIR mapping tutorial.

2.4 StructureMap

The StructureMap is a Resource presentation of the FHIR mapping language. Use the group.rule element to define (groups of) mapping rules. Below is an example of a mapping rule where the value of the source is copied to the target destination.

 <group> 
    <name value="Examples"/> 
    <typeMode value="none"/> 
    <input> 
      <name value="test"/> 
      <mode value="source"/> 
    </input> 
    <rule> 
      <name value="rule1"/> 
      <source> 
        <context value="Source"/> 
        <variable value="t"/> 
      </source> 
      <target> 
        <context value="Destination"/> 
        <transform value="copy"/> 
      </target> 
    </rule> 
  </group> 

Real-life examples


Core Specification

Here below is an example of a ConceptMap from the core specification. This ConceptMap shows the mapping from the HL7 FHIR ValueSet administrative-gender to the HL7 version 2 ValueSet v2-0001. The equivalence element defines how the concepts relate to one another. For example, Equal indicates that the source and target concepts have the exact same meaning and Wider indicates that the target concept is wider in meaning than the source concept.

ConceptMap 'v2 map for AdministrativeGender'

Canonical URLhttp://hl7.org/fhir/ConceptMap/cm-administrative-gender-v2
Published byHL7 (FHIR Project)
StatusDraft (since 2017-04-03T11:27:53+00:00)

v2 map for AdministrativeGender (http://hl7.org/fhir/ConceptMap/cm-administrative-gender-v2)

Mapping from administrative-gender to HL7 v2 Value Set 0001

Source ConceptEquivalenceDestination ConceptComment
Code [http://hl7.org/fhir/administrative-gender]Code [http://hl7.org/fhir/v2/0001]
male:EqualM
female:EqualF
other:WiderA
unknown:EqualU

The core specification also contains examples of using the FHIR mapping language. For example, the FHIR mapping language was used for the conversion of DSTU2 to STU3. In the R2 Conversions tab of a resource you can find examples of the use of the FHIR mapping language. For example, in the Patient resource the R2 Conversions tab describes StructureMaps for the conversion of R2 to R3 and the other way around.

Nictiz

Nictiz is the centre of expertise for standardization and eHealth in The Netherlands. HL7 Netherlands core and MedMij profiles are published on Simplifier. MedMij is a national project that aims to give Dutch citizens integrated access to all their health data in one personal health environment. FHIR is used as a standard to exchange health information between the involved parties. The profiles are based on standardized clinical building blocks called Health and Care Information Models (HCIM).

Below is an example of the use of elementdefinition.mapping in the HCIM BloodPressure (scroll down to see the actual mapping).


Exercise


In this exercise you will continue with the use case from the Start Profiling module. Use the Patient profile you created in this module or create a new Patient profile if you did not complete this exercise. Start by reading the case description. Here below are a couple of links that you may find useful during this exercise:

    Case description
    Hospital X wants to receive patient data from general practitioners. The hospital has decided to build conform the FHIR standard, starting with administrative data of patients and their general practitioner. They want to define a mapping from the local storage of their EHR data to the FHIR standard.

    The mapping from FHIR to the data fields in their EHR is as following:

    FHIR EHR
    Patient.name.family PatientAdmin.Surname
    Patient.name.given PatientAdmin.Name
    Patient.gender PatientAdmin.Gender
    Patient.birthDate PatientExtra.Birthdate
    Patient.deceasedBoolean PatientExtra.Died

    In addition, gender is stored as M (male), V (female) or U (unknown). These values need to be mapped to the administrative-gender ValueSet in FHIR.

Steps to follow

Exercise 1 - Add mappings to Patient profile

  1. Open your Patient profile in Forge
  2. Add a mapping system at the profile level (you can do so in the Properties tab). Add an Id and a logical name, for example 'Hospital X EHR'.
  3. Add the mappings to the elements using the ElementDefinition.mapping element. Select the mapping system you just added at the profile level and add the field of the EHR it maps to.

Exercise 2 - Create a StructureMap to map the EHR data fields to FHIR elements

  1. Create a new XML or JSON file that defines a StructureMap. The easiest way is to take one of the example resources on the HL7 FHIR downloads page as an example.
  2. Take a look at the specification and make sure that all mandatory elements are present in your XML or JSON file.
  3. Add a group element and a group.name (for example 'EHR to FHIR mapping').
  4. Define your source system in the group.input element.
  5. Use the group.rule element to define each mapping rule. No additional transformations of the data are required, so you can choose the value 'Copy' for the transform element.

Exercise 3 - Create a ConceptMap to map the gender values of the EHR to accepted FHIR codes

  1. Create a new XML or JSON file that defines a ConceptMap. The easiest way is to take one of the example resources on the HL7 FHIR downloads page as an example.
  2. Take a look at the specification and make sure that all mandatory elements are present in your XML or JSON file.
  3. Use the source and target elements to define the source and target of your mapping. Note that in this case there is no URL for the EHR data. You can use imaginary URLs.
  4. Use the group.element element to define each mapping.

Exercise 4 - Write the FHIR mapping language code for this mapping

  1. Give your map a name.
  2. Add a reference to your StructureDefinition and import the maps that you want to use.
  3. Add groups with transform rules.
  4. Suppose the hospital stores a prefix for family name as well in the data field PatientAdmin.PrefixSurname of the EHR. They want to concatenate this field with the PatientAdmin.Surname and add the concatenated value to the FHIR element Patient.name.family. Adjust the rule to make this happen.

Feedback


We are always looking for ways to improve our products. The Profiling Academy was built using our own IG-editor in Simplifier. If you have any feedback on this module or on our Profiling Academy in general, please leave a comment in the Issue Tracker of the project.


Get in touch


Start profiling

Most modules end with an exercise. Use Forge to start profiling yourself. Just contact us at simplifier@fire.ly if you need any help.

Learn more

Follow one of our predefined or tailor-made courses. We will make sure you know FHIR inside-out.

Need help or advice?

Let us assist you with your FHIR use case. Visit our company website to know more about our services or get into contact with Rien Wertheim right away.