HL7 Continuation Message

Introduction

HL7 Continuation Message: In HL7 it’s possible that you may have to deal with a legacy counter party system that has odd limits of the size of the messages they send. They might for instance be implemented using a mainframe system that can only cope with strings that 64k or less.

This page shows you how to use Iguana to stitch these parts together to make a single message.

Note: This solution assumes that messages are broken into two parts, and will need to be adapted for messages with more parts.

Before You Start

Part of the HL7 standard covers the ability to break larger messages containing say lab data, into smaller parts which then have to concatenated together by the receiving system.

How It Works

Here’s an example of the first part of the message where the presence of a DSC segment indicates that more data is to follow:

MSH|^~\&|SOFTMED^DIS|MGH|EGATE||20101110061841||MDM^T04|101110061841784|P|2.3.1||
EVN|
PID||1234567^^^MGH|||SMITH^THEODORE^E^^^^L^A||19350212|M||||||||||||
PV1|||W12^W1236^B||||018840|075325|||||||||018840|||||||||||||||||||||||||||20101025|20101103|
TXA|1|DIS||201011101818||201011030000|201011031346||018840||DEX|1307506|||||LA|||||^201011101818|
OBX|1|FT|&ZCR||DISCHARGE SUMMARY.br.brNAME: SMITH THEODORE E                   UNIT NUMBER: 123-45-67.br                                          FLOOR: W12 W1236B.brADMISSION DATE: 10/25/2010                DISCHARGE DATE: 11/03/2010.br.br.br.br.brPRINCIPAL DIAGNOSIS.brAVM.br.brASSOCIATED DIAGNOSES.brAltered mental status, Abnormal gait, Seizure disorder, Respiratory.brinsufficiency, Aphasia, Edema, Headache.br.brOPERATIONS AND PROCEDURES.br10/25/10: PROCEDURE: Left temporal craniotomy with microsurgical.brresection of arteriovenous malformation using BrainLab stereotactic.brguidance. Post-operative cerebral angiogram..br.br.brALLERGIES.brHCTZ (Unknown).brHeparin (Severe bleeding).brAspirin (severe bleeding).brALFUZOSIN (Unknown).brAMINOCAPROIC ACID (rhabdomyolysis).brALTEPLASE (severe bleeding).br.br.brHISTORY AND REASON FOR HOSPITALIZATION AND SIGNIFICANT FINDINGS.brThe patient is a 76yoM in for elective craniotomy for clipping of.brarteriovenous malformation with Dr. Ogilvy..br.brHPI: The patient has a complicated medical history including a h/o.brhereditary hemorrhagic telangiectasia (HHT) c/b cerebral, GI and.brpulmonary AVMs, chronic GIB, and progressive dyspnea. He is s/p.brBillroth II, duodenal resection for bleeding AVMs 6/19/2009 and s/p.brcoil embolization of left occipital artery to external jugular vein.brshunt vessel on 9/14/2010. He is transfusion dependent with chronic.brmelena/BRBPR and s/p cerebral bleed with resultant seizure. Pt. now.brpresents for surgical intervention for a temporal arteriovenous.brmalformation..br.brExam on admission:.brBP: 163/78 mm Hg.brAP: 95 bpm.brO2 Sat: 99%.brTemp: 97.8.brResp: 18.brHt: 66 inches.brWt: 153 lbs.brGeneral:  Patients is a well appearing, well nourished male in no.brapparent distress..brSkin:  Warm and dry to touch.  No sores, lesions, rashes, bruising or.brpetecchiae noted..brHEENT: Normocephalic, face symmetricalADD|
DSC|MGH-SM-1307506-20101110061841-1

This is the continuation part which indicates that it is a follow on message by having the continuation ID in it’s MSH message header segment:

MSH|^~\&|SOFTMED^DIS|MGH|EGATE||20101110061841||MDM^T04|101110061841784|P|2.3.1||MGH-SM-1307506-20101110061841-1
ADD|until cleared by this MD at follow-up.\.br\\.br\\.br\||||||S|||201011031346|
PR1||||||
ZTR|||||SOFTMED|MGH||||DE^DEX Discharge Summary^MGH-RPTL-REPTYPE|This article has not been written.

The example in the following three pages explains how to leverage the Translator to solve this problem.

The code for this example is effectively “plug and play” as it will automatically create its own SQLite database and tables if they do not exist.

Algorithm [top]

The algorithm is easy. We create a database table “continuation” which is used to store the messages that need continuation data.

This will have a simple structure:

Column Name Description
ContinuationId (key) Unique code identifying the continuation number. Needs to be large enough to store the keys, say 100 characters
Message The raw HL7 message. Should be about 100k in size depending on the largest message size.

When we get a message that needs us to wait for a continuation part we insert it into this table using the Continuation Pointer value as the key value for the ContinuationId.

Then when we get the remainder message we can recall that data from the table and parse it and combine the data together with the original message. Fortunately Iguana has no trouble coping with messages larger than 64k in length!

For simplicity we only show how to process the continuation message, the concatenated message will need further processing/saving etc (code for this is not included).

Example Code [top]

This was a fun problem to solve with the Translator, and as if often the case the solution is quite simple

This is what we need to do:

  • Identify (partial) messages with continuations and save them to the database
  • Identify the continuation messages and retrieve the initial message
  • Stitch the messages together to create a complete HL7 message

Note: This example assumes that messages are broken into two parts, and will need to be adapted to handle more parts.

How It Works

The first step is to identify (partial) messages with continuations and save them to the database.

First we create the SQLite database and tables if they do not exist. Then we test for the existence of the DSC continuation segment and use the cont module to push the message into the database using the continuation ID as the primary key.

Save a continued message to the Database

Here is a screen shot:
main code

Note: to ensure that the code works on any system the DB and VMD files do not specify a path and therefore default to using the Iguana install directory. You can customize this for your system by changing SQLITE_DB and VMD_FILE variables to something like

SQLITE_DB='D:tempcontinuation.sqlite' 
VMD_FILE='D:tempContinuation.vmd'

The PushContinuation() function uses cont.put() to save the message to the database:

push continuation

The cont.put() function inserts the message associated with that Continuation ID into the database, or replaces it if it already exists. If you are interested in in how this works you can look at the code for the module (it uses the SQL REPLACE keyword).

Retrieve a continued message from the Database

Now when we get the continuation message we simply retrieve the first message and concatenate the data together.

When we get a message with a continuation pointer in the MSH segment we do this:

  1. Fetch the original HL7 message from the database using the continuation pointer
  2. Extract the first part of the lab text from the OBX segment
  3. Strip off the ADD part of the lab text
  4. Concatenate it together with a space to the end part of the lab data
  5. Translate .br escape sequences to n

This formats the message in a nice human-readable format. Obviously, you can process the in other ways, whatever is suited to your needs.

Here is a screenshot:

code

By clicking on the return annotation of the MergeText() routine we can see the full lab result in human-readable format:
human readable form

And as you can see the continuation string “until cleared by this MD at follow-up.” has been appended.

What’s Next?

We have shown you how the code to concatenate a two part message works, the next step is to add your own code to process the concatenated message. The sample code is available on the next page.

If you need to support messages with more than two parts you will need to modify the code. One way to do this would be to change the FetchContinuation() function to recursively retrieve all the continuations for a message.

Please contact support at support@interfaceware.com if you need more help.

Source Code [top]

The code is specific to SQLite and will need tweaking to work with other databases.

This is the SQL used to create the Continuation table for SQLite. We could have generated the table from the VMD file, but as it will never change it is simpler to hard code it.

create table

Because SQLite uses a “dynamic type system” the the Message field will happily store a string of any length. In fact in SQLite the datatype is only a recommendation and if we had declared Message as an integer we could still store string data in it. For more information see Datatypes In SQLite Version 3.

Other databases use strict static typing, something like this should work with most other database servers:

CREATE TABLE Continuation (
   ContinuationId VARCHAR(100) NOT NULL,
   Message VARCHAR(100000),
   PRIMARY KEY (ContinuationId)
);

Sample Data

Here’s an example of the first part of the message where the presence of a DSC segment indicates that more data is to follow:

MSH|^~&|SOFTMED^DIS|MGH|EGATE||20101110061841||MDM^T04|101110061841784|P|2.3.1||
EVN|
PID||1234567^^^MGH|||SMITH^THEODORE^E^^^^L^A||19350212|M||||||||||||
PV1|||W12^W1236^B||||018840|075325|||||||||018840|||||||||||||||||||||||||||20101025|20101103|
TXA|1|DIS||201011101818||201011030000|201011031346||018840||DEX|1307506|||||LA|||||^201011101818|
OBX|1|FT|&ZCR||DISCHARGE SUMMARY.br.brNAME: SMITH THEODORE E                   UNIT NUMBER: 123-45-67.br                                          FLOOR: W12 W1236B.brADMISSION DATE: 10/25/2010                DISCHARGE DATE: 11/03/2010.br.br.br.br.brPRINCIPAL DIAGNOSIS.brAVM.br.brASSOCIATED DIAGNOSES.brAltered mental status, Abnormal gait, Seizure disorder, Respiratory.brinsufficiency, Aphasia, Edema, Headache.br.brOPERATIONS AND PROCEDURES.br10/25/10: PROCEDURE: Left temporal craniotomy with microsurgical.brresection of arteriovenous malformation using BrainLab stereotactic.brguidance. Post-operative cerebral angiogram..br.br.brALLERGIES.brHCTZ (Unknown).brHeparin (Severe bleeding).brAspirin (severe bleeding).brALFUZOSIN (Unknown).brAMINOCAPROIC ACID (rhabdomyolysis).brALTEPLASE (severe bleeding).br.br.brHISTORY AND REASON FOR HOSPITALIZATION AND SIGNIFICANT FINDINGS.brThe patient is a 76yoM in for elective craniotomy for clipping of.brarteriovenous malformation with Dr. Ogilvy..br.brHPI: The patient has a complicated medical history including a h/o.brhereditary hemorrhagic telangiectasia (HHT) c/b cerebral, GI and.brpulmonary AVMs, chronic GIB, and progressive dyspnea. He is s/p.brBillroth II, duodenal resection for bleeding AVMs 6/19/2009 and s/p.brcoil embolization of left occipital artery to external jugular vein.brshunt vessel on 9/14/2010. He is transfusion dependent with chronic.brmelena/BRBPR and s/p cerebral bleed with resultant seizure. Pt. now.brpresents for surgical intervention for a temporal arteriovenous.brmalformation..br.brExam on admission:.brBP: 163/78 mm Hg.brAP: 95 bpm.brO2 Sat: 99%.brTemp: 97.8.brResp: 18.brHt: 66 inches.brWt: 153 lbs.brGeneral:  Patients is a well appearing, well nourished male in no.brapparent distress..brSkin:  Warm and dry to touch.  No sores, lesions, rashes, bruising or.brpetecchiae noted..brHEENT: Normocephalic, face symmetricalADD|
DSC|MGH-SM-1307506-20101110061841-1

This is the continuation part which indicates that it is a follow on message by having the continuation ID in it’s MSH message header segment:

MSH|^~&|SOFTMED^DIS|MGH|EGATE||20101110061841||MDM^T04|101110061841784|P|2.3.1||MGH-SM-1307506-20101110061841-1
ADD|until cleared by this MD at follow-up..br.br.br||||||S|||201011031346|
PR1||||||
ZTR|||||SOFTMED|MGH||||DE^DEX Discharge Summary^MGH-RPTL-REPTYPE|This article has not been written.

Sample Code

This is vmd file used in the example: Continuation.vmd

This is the main routine:

require 'cont'

-- change the locations of the VMD and DB files as required
-- in this case (no path specified) the path defaults to the Iguana install directory
SQLITE_DB='continuation.sqlite' 
-- vmd must be in XML format
VMD_FILE='Continuation.vmd'

conn = db.connect{
   api=db.SQLITE,
   name=SQLITE_DB
}

function main(Data)   
   -- create the database file and tables if it does not exist
   local r=conn:query('SELECT * FROM sqlite_master') 
   if #r==0 then CreateTable() end

   local Msg = hl7.parse{data=Data, vmd=VMD_FILE}
   if not Msg.DSC:isNull() then
      PushContinuation(Msg, Data)
      return
   end
   if Msg.MSH[14] then 
      trace('We have a continuation.') 
      local T = FetchContinuation(Msg)
   end
   ----------------------------------------------------
   -- add code here to process the concatenated message
   ----------------------------------------------------
end

function PushContinuation(Msg,Data)
   local Id = Msg.DSC[1]:nodeValue()
   trace("Encountered continuation segment, ID = "..Id)
   cont.put(Id, Data)
end

function FetchContinuation(Msg)
   local OrigMsg = cont.get(Msg.MSH[14]:nodeValue())
   if not OrigMsg then
      error("Could not find original message for "..Msg.MSH[14]:nodeValue())
   end
   local Orig = hl7.parse{vmd=VMD_FILE, data=OrigMsg}
   local Text = MergeText(Orig, Msg)
   return Text
end

function MergeText(Msg1, Msg2) 
   local T = Msg1.OBX[5][1][1]:nodeValue()
   T = T:sub(1, #T-3)
   trace(Msg2.ADD[1]:nodeValue())
   T = T.." "..Msg2.ADD[1]
   T = T:gsub(".br", "\n")
   return T
end

-- create continuation table - the SQL used is ***SQLite*specific***
function CreateTable()
   local Sql=
   'CREATE TABLE IF NOT EXISTS Continuation\n'..
   '(\n'..
     'ContinuationId TEXT(255) NOT NULL PRIMARY KEY,\n'..
     'Message TEXT(255) NULL\n'..
   ');' 
   trace(Sql)
   conn:execute{sql=Sql,live=true}
end

This is the cont module:

cont = {}

function cont.get(Id, DbName)
   local Sql = 
     'SELECT * FROM Continuation WHERE ContinuationId = '..conn:quote(Id)
   local R = conn:query(Sql)
   if (#R == 0) then return nil end
   return R[1].Message:nodeValue()
end

function cont.put(Id, Data)
   trace(Esc,conn)
   local Sql = 
     "REPLACE INTO Continuation(ContinuationId, Message)"..
     " VALUES("..conn:quote(Id)..","..conn:quote(Data)..")"
   trace(Sql)
   conn:execute{sql=Sql,live=true} 
end
Tagged: