HL7v2 to FHIR - customizing code mappings
Override standard HL7v2 code mappings, add your local table values and keep unknown codes preserved in the output.
HL7v2 and FHIR express the same concepts through different codes - an HL7 gender of M is FHIR's male, and a patient class of I is the encounter class IMP. The conversion carries the standard translation tables built in, so PID-8 gender, PV1-2 patient class, PID-16 marital status, order and result statuses and the other coded fields come out as FHIR codes without any setup.
What remains for you are the codes that are yours alone. A local table value needs one line in the configuration file, and a code with no mapping at all stays preserved in the output.
Overriding and adding codes
Hospital systems use their own local values - a patient class of P that means outpatient, a locally defined result status. The [codes] section of the configuration file adjusts any map, one subsection per map, each line mapping an HL7 code to the FHIR target code:
[codes]
# PV1-2 - P is our local code for ambulatory
[[patient_class]]
P=AMB
# PID-8 - map our local code D to unknown
[[administrative_sex]]
D=UNK
An override wins over the standard value for that code, all other codes in the map keep their standard translations, and codes new to the map are added. With the file above, msg.to_fhir(config='my-mappings') turns a PV1-2 of P into:
The map names
The subsection names in [codes] are the map names below:
| Map | Source field |
|---|---|
| administrative_sex | PID-8 |
| marital_status | PID-16 |
| name_type | XPN name type, e.g. PID-5.7 |
| address_type | XAD address type, e.g. PID-11.7 |
| telecom_use | XTN use code, e.g. PID-13.2 |
| telecom_equipment_type | XTN equipment type, e.g. PID-13.3 |
| patient_class | PV1-2 |
| patient_class_status | PV1-2, deciding the Encounter status |
| allergy_category | AL1-2 |
| allergy_type | AL1-2 |
| allergy_criticality | AL1-4 |
| allergy_severity | AL1-4 |
| diagnosis_type | DG1-6 |
| abnormal_flags | OBX-8 |
| observation_result_status | OBX-11 |
| order_status | ORC-1 |
| result_status | OBR-25 |
| filler_status | SCH-25 |
| completion_status | RXA-20 |
Unknown codes
A code with no mapping - standard or configured - does not stop the conversion and no value is invented in its place:
- Optional elements, e.g.
Patient.genderorPatient.maritalStatus, are left unset - Required elements get a safe default - an Observation status becomes
unknown, an Encounter class becomes the null-flavorUNK
Either way the original code is preserved as an extension on the resource, naming the field it came from:
from zato.hl7v2 import parse_hl7
raw = (
'MSH|^~\\&|SENDER|FACILITY|RECEIVER|FAC|20260315101112||ADT^A01^ADT_A01|CTL001|P|2.9\r'
# PID-8 contains X, which is not a standard administrative sex code ..
'PID|||12345^^^HOSP^MR||SMITH^JOHN||19800115|X\r'
# .. and neither is Q a standard patient class in PV1-2.
'PV1|1|Q\r'
)
msg = parse_hl7(raw, validate=False)
bundle = msg.to_fhir()
for entry in bundle.entry:
resource = entry.resource.to_dict()
if 'extension' in resource:
for item in resource['extension']:
print(item['url'], '->', item['valueString'])
The X sits on the Patient and the Q on the Encounter, so the values stay available for inspection - and the URLs point at the local codes worth adding to your [codes] section. The extensions share their base URL with Z-segment extensions and the [extensions] section of the configuration file changes it.
Verifying a conversion is complete
get_conversion_warnings returns the list of everything a conversion could neither map nor preserve. An empty list confirms the whole message made it into the bundle - a useful assertion in tests that convert your own traffic:
from zato.hl7.mappings import get_conversion_warnings
warnings = get_conversion_warnings(bundle)
assert warnings == []
See also
| Page | What it covers |
|---|---|
| Configuration | The .ini file the codes section lives in, with every other setting |
| Z-segments | The other kind of extension, built from custom segments |
| What you get per message | The resources the coded fields end up on |
Learn more
Schedule a meaningful demo
Book a demo with an expert who will help you build meaningful systems that match your ambitions
"We evaluated 12 integration platforms and Zato was the only one to score 100%."
Philip Zuñiga, Assistant Professor, University of the Philippines