Series by Stefan Spiska, Senior Backend Developer, PEN, vitagroup HIP
Part 2 of the series "Vendor neutral interoperability with openEHR and HL7 FHIR"
The first step in integration is typically patient onboarding. In most hospital settings, when a patient is created in the Hospital Information System (HIS), other systems within the hospital are notified by sending an HL7 v2 ADT message, such as the following:
MSH|^~\&|MIRTH|MIRTH_CONNECT|HIS001|MIRTH_CONNECT|20231010121200||ADT^A01|MSG0000001|P|2.3|||NE|NE|CO|8859/1|ES-CO
PID|||6537077^^^^CC||Smith^John||19860705|M
PV1||I|||||||||||||||||22cce64c-8ea1-4ac9-8974-163087171c85
HL7 v2 defines a set of structured messages, each consisting of different segments separated by line breaks. Each segment is made up of fields separated by a pipe (|), which can be further divided into components (^) and subcomponents (&).
Common HL7 v2 Segments
- MSH (Message Header): Contains metadata about the message.
- PID (Patient Identification): Holds patient demographic details.
- PV1 (Patient Visit): Captures information about the patient's hospital encounter.
Example Breakdown
- MSH-9 (ADT^A01): Message type ADT (Admission, Discharge, Transfer) Admit/Visit Notification.
- PID-5 (Smith^John): Patient Name.
- ** - PID-5.1 (Smith): Family Name.
- ** - PID-5.2 (John): Given Name.
When a patient is admitted, an HL7 ADT (Admission, Discharge, Transfer) message is generated by the Hospital Information System (HIS), to inform 3rd party systems in the hospital. The HIP HL7v2 Connector receives the HL7v2 mesages and forwards them towards HIP.
Convert HL7v2 to a FHIR Patient and a FHIR Encounter
PSLP - Protocol Specific Path Language
To facilitate data mapping between different formats, vitagroup developed PSPL (Protocol Specific Path Language) - a path based navigation and extraction language.
With PSPL, integration experts can define mappings between various data formats. Elements are identified using expressions similar to XPath or FHIRPath. The language supports operations such as traversal, selection, and filtering of hierarchical data models.
Using PSPL, we can define mappings:
- The Patient Identification (PID) segment to a FHIR Patient resource
- The Patient Visit (PV1) segment to a FHIR Encounter resource
Defining a Trigger Condition
Before applying mappings, we must define when they should be triggered. The following condition ensures that the mapping applies to any incoming message of type "ADT^A01" (Admit/Visit notification), as specified in the message header:
"createConditions": [
{
"condition" : "MSH.9",
"anyExpectedValue" : [
"ADT^A01"
]
}
]
Mapping an HL7 v2 PID segment to a FHIR Patient resource
Next, we define a mapping between an HL7 v2.3 PID segment and an HL7 FHIR R4 Patient resource:
"sourceProtocol": "HL7v2",
"sourceProtocolVersions": [
"2.3"
],
"sourceType": "PID",
"storageProtocol": "FHIR",
"storageProtocolVersion": "R4",
"storageType": "Patient",
A series of mappings between segments and elements is then applied. The snippet below maps PID.5.1 (Family Name) to FHIR Patient’s name.family:
{
"storageClass": "String",
"storagePath": "name[isList: true].family",
"attributes": {
"value": {
"type": "rw",
"sourcePath": "PID.5.1",
"dataType": "String"
}
}
}
The function isList: true ensures that the name element is represented as a JSON array instead of a single JSON object.
Resulting FHIR Patient Resource
Thus for the incoming Hl7 v2 message we create a Patient resource as follows:
{
"resourceType": "Patient",
"name": [
{
"family": "Smith",
"given": [
"John"
]
}
]
...
}
Mapping an HL7 v2 PV1 segment to a FHIR Encounter resource
Some transformations require additional logic. For instance, when creating an Encounter from the PV1 (Patient Visit) segment, PV1-2 contains Patient Class (Inpatient, Emergency, etc.). Since PV1-2 uses a HL7 v2 value set, it must be translated into the corresponding FHIR value set (FHIR Encounter Class ValueSet).
See the following Transformation definition:
{
...
"definition": {
"sourceProtocol": "HL7v2",
"sourceProtocolVersions": [
"2.3"
],
"sourceType": "PV1",
"storageProtocol": "FHIR",
"storageProtocolVersion": "R4",
"storageType": "Encounter",
"transformations": [
{
"storageClass": "String",
"storagePath": "class.code",
"attributes": {
"value": {
"type": "rw",
"sourcePath": "PV1.2[convert: '\"E\" -> \"EMER\"; \"I\" -> \"IMP\"; \"O\" -> \"AMB\"; \"P\" -> \"PRENC\";']",
"dataType": "String"
}
}
},
{
"storageClass": "String",
"storagePath": "class.system",
"attributes": {
"value": {
"type": "static",
"sourcePath": "",
"staticValue": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
}
},
"conditions": [
{
"sourcePath": "PV1.2",
"anyExpectedValue": [
"E","I","O","P"
]
}
]
}
...
],
...
"createConditions": [
{
"condition" : "MSH.9",
"anyExpectedValue" : [
"ADT^A01"
]
}
]
}
}
Explanation of transformations
- convert function:
- Maps HL7 v2 PV1-2 codes (E, I, O, P) to the FHIR equivalent values (EMER, IMP, AMB, PRENC).
- Static mapping for terminology system:
- If a value from PV1-2 is found, a terminology system URL is added (http://terminology.hl7.org/CodeSystem/v3-ActCode).
As a Result we get a correct Fhir Fhir coding:
"class" : [{
"coding" : [{
"system" : "http://terminology.hl7.org/CodeSystem/v3-ActCode",
"code" : "IMP"
}]
}]
For more complex scenarios a FHIR terminology service and concept maps can be used.
Linking the FHIR Encounter to the FHIR Patient
All that left is to connect the Patient and Encounter resource. With the following mapping we ensure that the created Encounter references the create Patient as subject.
{
...
"definition": {
"sourceProtocol": "HL7v2",
"sourceProtocolVersions": [
"2.3"
],
"sourceType": "PV1",
"storageProtocol": "FHIR",
"storageProtocolVersion": "R4",
"storageType": "Encounter",
"transformations": [
{
"storageClass": "String",
"storagePath": "subject.reference",
"attributes": {
"value": {
"type": "rw",
"sourcePath": "PID.3.1[isIdValue: 'Patient']",
"dataType": "String"
}
}
}
...
],
...
"createConditions": [
{
"condition" : "MSH.9",
"anyExpectedValue" : [
"ADT^A01"
]
}
]
}
}
Final Workflow
Now, whenever an HL7 ADT message arrives at HIP, the defined mappings are triggered, and the HIP-Bridge executes the following actions:
- Create a FHIR Patient Resource and a FHIR Encounter from the HL7 ADT message
- Links the Encounter to the Patient
- Stores Encounter and Patient in the FHIR-Store.
- Should storing fail because the validation does not pass or any other error, a transaction rollback is conducted across all services to ensure data integrity.
Top comments (0)