Skip to main content

Working with HL7

HL7 v2 is the most widely used data standard in the healthcare industry. But not all systems and devices use the same version and can have customizations. Thats where HL7 filtering and mapping becomes essential.

Creating HL7 interfaces in Iguana follows a simple repeatable pattern:

  1. Parsing the inbound HL7 messages.

  2. Filtering unwanted messages.

  3. Mapping(translating) or transforming the messages.

  4. Queueing messages for the downstream component.

Let's build an HL7 Mapping component.

STEP 1: On the Dashboard, create a custom component, call it "HL7 Mapping", and open the Translator

Create a Component using the Custom Component, call it Working with HL7.

In the component card, open the Translator by clicking Edit > Make a Copy and Edit.

STEP 2: Add sample data to the project

So we can leverage the Translator's Auto-complete and the Annotations, let's add this sample HL7 ADT^A01 message:

MSH|^~\&|MESA_ADT|XYZ_ADMITTING|iFW|ZYX_HOSPITAL|||ADT^A01|103102|P|2.4||||||||   
EVN||200007010800||||200007010800
PID|||583295^^^ADT1||DOE^JANE||19610615|M||2106-3|123 MAIN STREET ^^GREENSBORO^NC^27401-1020|GL|(919)379-1212|(919)271-3434~(919)277-3114||S||PATID12345001^2^M10|123456789|9-87654^NC
NK1|1|BATES^RONALD^L|SPO|||||20011105
PV1||E||||||5101^NELL^FREDERICK^P^^DR|||||||||||V1295^^^ADT1|||||||||||||||||||||||||200007010800||||||||
PV2|||^ABDOMINAL PAIN
OBX|1|HD|SR Instance UID||1.123456.2.2000.31.2.1||||||F||||||
AL1|1||^PENICILLIN||PRODUCES HIVES~RASH
AL1|2||^CAT DANDER
DG1|001|I9|1550|MAL NEO LIVER, PRIMARY|19880501103005|F||
PR1|2234|M11|111^CODE151|COMMON PROCEDURES|198809081123
ROL|45^RECORDER^ROLE MASTER LIST|AD|CP|KATE^SMITH^ELLEN|199505011201
GT1|1122|1519|BILL^GATES^A
IN1|001|A357|1234|BCMD|||||132987
IN2|ID1551001|SSN12345678

STEP 3: Parse the inbound HL7 messages with hl7.parse

First, use hl7.parse{} to parse the HL7 message so we can break it down and get it ready to transform

local msg, name, warning = hl7.parse{vmd="hl7.vmd", data=Data}   

In order to parse an HL7 message, you need to pass a vmd and the data to be parsed. Review Creating a VMD to create a VMD for this tutorial.

hl7.parse{} returns three values:

  • The parsed message as an HL7 node tree.

  • The name of the HL7 message type as defined in the VMD - we can use this in our next step to apply filtering rules based on message type.

  • Data integrity warnings for missing message segments or fields expected.

STEP 4: Filter unwanted messages based on message type

If you are applying multiple filtering rules on inbound messages, it is best to create modularize your script and call a filter function you define - see Filtering Messages.

For this example, we will simply use conditional logic to skip any messages not of the type “ADTA01“.

-- filter unwanted messages   
if name ~= "ADTA01" then
-- Skip processing if the message type is not ADT^A01
return
end

To test this, we can use the sample data and annotations to view our filtering logic. First, create a Catchall Message Definition to catch all other messages that do not match “ADTA01“.

  • Open your VMD file and create a Message Definition called “Catchall“.

  • Add it to the Matching Rules - use the asterisks * to match all other messages that do not match ADTA01.

Add this ORM^O01 message to your sample data and view the results:

MSH|^~\&|MESA_OP|XYZ_HOSPITAL|iFW|ABC_RADIOLOGY|||ORM^O01|101104|P|2.3||||||||   
PID|1||20891312^^^^EPI||APPLESEED^JOHN^A^^MR.^||19661201|M||AfrAm|505 S. HAMILTON AVE^^MADISON^WI^53505^US^^^DN |DN|(608)123-4567|(608)123-5678||S|| 11480003|123-45-7890||||^^^WI^^
PD1|||FACILITY(EAST)^^12345|1173^MATTHEWS^JAMES^A^^^
PV1|||^^^CARE HEALTH SYSTEMS^^^^^||| |1173^MATTHEWS^JAMES^A^^^||||||||||||610613||||||||||||||||||||||||||||||||V
ORC|NW|987654^EPIC|76543^EPC||Final||^^^20140418170014^^^^||20140418173314|1148^PATTERSON^JAMES^^^^||1173^MATTHEWS^JAMES^A^^^|1133^^^222^^^^^|(618)222-1122||
OBR|1|363463^EPC|1858^EPC|73610^X-RAY ANKLE 3+ VW^^^X-RAY ANKLE ||||||||||||1173^MATTHEWS^JAMES^A^^^|(608)258-
8866||||||||Final||^^^20140418170014^^^^|||||6064^MANSFIELD^JEREMY^^^^||1148010^1A^EAST^X-RAY^^^|^|
DG1||I10|S82^ANKLE FRACTURE^I10|ANKLE FRACTURE||

STEP 5: Apply mappings

See Mapping Messages for common mapping methodologies.

Tip

Make sure you toggle back to your first sample message (ADT^A01) that does not get filtered out to leverage the annotations and autocomplete when building the mappings!

We'll cover a few of these in this tutorial:

  1. Hardcoded simple assignment: Map the given name to 'James'.

  2. String Manipulation:

  3. Map the last name to use lowercase and then capitalize the last name 'Doe'.

  4. Trim white space from the street address to remove unwanted white space from the right side.

  5. Code Lookups:

  6. Import the Codemap Library and create a codeSet of Sending Applications to map.

Your mappings should look like this (note the results in the annotations):

STEP 6: Queue the translated messages

Use queue.push{} to send messages to a linked downstream component. Make sure the outbound message is converted to a string before pushing to the queue!

Commit your changes to save the component project locally.

Your completed interface script:

require "codemap.map"   

function main(Data)

-- Parse inbound HL7
local msg, name, warning = hl7.parse{vmd='demo.vmd', data=Data}

-- Filter unwanted messages
if name ~= "ADTA01" then
-- Skip processing if the message type is not ADT^A01
return
end

-- Map fields
-- (1) hardcode values
msg.PID[5][2] = 'James'

-- (2) string manipulation
msg.PID[5][1][1]:lower():capitalize()
msg.PID[11][1][1]:trimRWS()

-- (3) lookup values
local codeSet = codemap.map({
ABC_HOSPITAL = 'ABC',
XYZ_ADMITTING = 'XYZ'
})
msg.MSH[4][1] = codeSet[msg.MSH[4][1]]

-- Queue message to downstream component
queue.push{data=msg:S()}

end