Daniel Kutac · Feb 25, 2016

Programmatically creating HL7v2 message, anyone?

A customer needs to assemble a HL7v2 ADR A19 (ADT Response - Patient Query) message programmatically, inside Ensemble.

Does anyone have an example of how can one create a HL7v2 message programmatically? 

So far, I could only find a brief note in WRC mailing, so I followed it. I have scubclassed EnsLib.HL7.MsgRouter.RoutingEngine class and implemented OnConstructReply() method but it seems to be NEVER called. I made sure this class is used as BP instead of original one, bound it to the routing rules, but no luck so far.

Can anyone advice?


Dan Kutac

6 0 9 1,152
Log in or sign up to continue

Is there some reason you can't directly use the class  EnsLib.HL7.Message?

This class has methods like ImportFromFile() and ImportFromString().

Well, there is no file available, just data that sits inside Ensmeble as Ensemble is also clinical system -> source of data, so it's not just a router in bvetween two systems.

Sounds like a use case for a DTL if you ask me. Even if it's not and you have to be very generic, I would start with a DTL and take a look at the compiled code as a starting point. 

Hi Daniel: I had started on this and I was able to produce few variants (AD*, OM* etc.) . You can add more segments, more randomization etc. I'll have to dig out the code. It was part of a larger project...

let me know

Yes, Luca, that would help me. 

Thank you!


there are lots of ways of doing this. I find thta building the segment data into strings is often the easiest way to do it because you can see what you have and mistakes are easier to avoid.

The example below builds strings with random data but you could be pulling it form a database. 

If you want to be more sophistcated you could use the SetValueAt() method of an HL7 Segment.

As Stefan says, looking at the generated code for a data transform can often give you good ideas.



//random values. These could be pulled from an application
set PID1=(1+$r(9))_$r(9999999)
set PID2=(1+$r(9))_$r(9999999)
set PID3=(1+$r(9))_$r(9999999)
set PID4=(1+$r(9))_$r(9999999)
set CID=(1+$r(9))_$r(9999999)
set PAC=(1+$r(9))_$r(9999999)

set firstname=##class(%PopulateUtils).FirstName()
set lastname=##class(%PopulateUtils).LastName()

set hl7=##class(EnsLib.HL7.Message).%New()
set hl7.DocType="2.5:ADT_A01"

set tSeg1=##class(EnsLib.HL7.Segment).ImportFromString("MSH|^~\&|HQ|A|||20070222140835||ADT^A01|1"_$r(99999999)_"R"_$R(99999999)_"|D|2.2||||||||||2.2b")

set tSeg2=##class(EnsLib.HL7.Segment).ImportFromString("EVN|A01|200702221400||ADM|MPACPB")
set tSeg3=##class(EnsLib.HL7.Segment).ImportFromString("PID|1|"_PID1_"|"_PID2_"^^^A^MR~"_PID3_"^^^B^PI~"_PID4_"^^^C^PI||"_lastname_"^"_firstname_"||20010101|U||W|122 BIRDSEED ROAD^^SKOKIE^IL^60077^US^^COOK|COOK|(847)676-2211||ENG|S|NON|3000018947054|111-11-1111|||||||||||N||||||||||||||||||||N")

set tSeg4=##class(EnsLib.HL7.Segment).ImportFromString("PD1|||||||O")
set tSeg5=##class(EnsLib.HL7.Segment).ImportFromString("PV1|1|I|E3E^3404^01^E|U|||000764^LERNER^DAVID JOSEPH^^MD^DR|||MED||||R|||000764^LERNER^DAVID JOSEPH^^MD^DR|I|7054|5^20070223|||||||||||||||||||E|||||200702221400|||||||A||000764^LERNER^^^MD^DR")
set tSeg6=##class(EnsLib.HL7.Segment).ImportFromString("PV2||P")
set tSeg7=##class(EnsLib.HL7.Segment).ImportFromString("DG1|1|FF|^OOO^FF||20050101|A|||||||||0||O")
set tSeg8=##class(EnsLib.HL7.Segment).ImportFromString("GT1|1|300001894^^^A^PI|BOOBOO^POOPOO||122 BIRDSEED ROAD^^SKOKIE^IL^60077^US^^COOK|(847)676-2211||20010101|U||P|111-11-1111||||001000^NONE|^^^^^US|||N")
set tSeg9=##class(EnsLib.HL7.Segment).ImportFromString("ZPI|1|N|||||||||20070220|N||^C|001000^NONE|^^^^^US")
set tSeg10=##class(EnsLib.HL7.Segment).ImportFromString("ZPV|1||||||||||N||||O||")
set tSeg11=##class(EnsLib.HL7.Segment).ImportFromString("ZP2|1|x|dgcode|")

set tsc=hl7.SetSegmentAt(tSeg1,1)

set tsc=hl7.InsertSegmentAt(tSeg2,2)
set tsc=hl7.InsertSegmentAt(tSeg3,3)

set tsc=hl7.InsertSegmentAt(tSeg4,4)
set tsc=hl7.InsertSegmentAt(tSeg5,5)
set tsc=hl7.InsertSegmentAt(tSeg6,6)
set tsc=hl7.InsertSegmentAt(tSeg7,7)
set tsc=hl7.InsertSegmentAt(tSeg8,8)
set tsc=hl7.InsertSegmentAt(tSeg9,9)
set tsc=hl7.InsertSegmentAt(tSeg10,10)
set tsc=hl7.InsertSegmentAt(tSeg11,11)

Thank you David,

but I have different problem. I admit my HL7v2 knowledge is limited. I have seen several scenarios where Ensemble acts as HL7 router, just accepting message at one end (service) and routing it to another end (operation) and eventually automatically sending ACK back to originator. 

But this case is different. Client is expecting immediate response - the ADR^A19 message. So I now have multiple ways of constructing response, but how do I actually return it back to the caller?



Ok, I thing I got it now.

I just need to subclass a service and implement OnConstrucRepply() method and compose the pReplyDoc as needed.



It looks as if  you are receiving a patient query (QRY_A19) so the approach depends on where the information for the reply is going to come from. 

If the BS has all that information in Ensemble then you can just do as you suggest. If it has to come from a downstream system then you might have to use business service setting 'AckMode=Application'. This means the business service will wait for an ACK  to be sent to it from downstream. If that response is exactly what you want, you can use it. Otherwise you will still have to override OnConstructReply to use the ACK to build exactly what you need.