Jayant Singh Website - Healthcare IT Blog

HL7 Parsing in C#

I learned a little bit of nHAPI during my last post on HL7 over HTTP and wanted to use it for a utility that I am working on. But some more research on nHAPI influenced me to develop my own small library in C#.

nHAPI is a great library and I do not want to compete with it. One of the reasons I decided to write a small library is I needed very basic features like read any HL7 message, evaluate some fields, update some fields, get updated HL7 message, generate ACKs. At this time I have decided to overlook message type or trigger event specific features/validations. However it performs basic validations to ckeck message header, format of segment names, delimiters etc.

This library treats every message in same manner while parsing HL7 messages. After successfull parsing it provides all the components of HL7 message like segments, fields (with repetitions), components, subcomponents in easily accessible way.

I do not want to claim it as HL7 Parsing Library. But it provides some basic features and simple ways to access those features.


Now let’s see how to use this library:


Create a Message object and pass raw HL7 message in text format


Message message = new Message(strMsg);

Parse this message

bool isParsed = false;
try
{
    isParsed = message.ParseMessage();
}
catch(Exception ex)
{
    //handle the exception
}

Now let’s see some of the functions, Please note indexes are zero based, so if you access FieldList[3], it’s actually a fourth field.


Accessing Segments


Get list of all segments

List<Segment> segList = message.Segments();

Get List of list of repeated segments by name For example if you have multiple IN1 segments

List<Segment> IN1List = message.Segments("IN1");

access a particular occurrence from multiple IN1s you can provide the index, please note index 1 will give you 2nd element from list

Segment IN1_2 = message.Segments("IN1")[1];

Get count of IN1s

int countIN1 = message.Segments("IN1").Count;

Access first occurrence of any segment

Segment IN1 = message.DefaultSegment("IN1");

OR

Segment IN1 = message.Segments("IN1")[0];

Accessing Fields


Access field values

String SendingFacility = message.getValue("MSH.4");

OR

String SendingFacility = message.DefaultSegment("MSH").Fields(4).Value;

OR

String SendingFacility = message.Segments("MSH")[0].Fields(4).Value;

Check if field is componentized

bool isComponentized = message.Segments("PID")[0].Fields(5).IsComponentized;

OR

bool isComponentized = message.IsComponentized("PID.5");

Check if field has repetitions

bool isRepeated = message.Segments("PID")[0].Fields(3).HasRepetitions;

OR

bool isRepeated = message.HasRepeatitions("PID.3");

Get list of repeated fields

List<Field> repList = message.Segments("PID")[0].Fields(3).Repetitions();

Get particular repetition i.e 2nd repetition of PID.3

Field PID3_R2 = message.Segments("PID")[0].Fields(3).Repetitions(2);

Update value of any field i.e. to update PV1.2 – patient class

message.setValue("PV1.2", "I");

OR

message.Segments("PV1"[0];).Fields(2).Value = "I";

You can access some of the required MSH fields with properties

String version = message.Version;
String msgControlID = message.MessageControlID;
String messageStructure = message.MessageStructure;

Accessing Components


Access particular component i.e. PID.5.1 – Patient Family Name

String PatName1 = message.getValue("PID.5.1");

OR

String PatName1 = message.Segments("PID")[0].Fields(5).Components(1).Value;

Check if component is sub componentized

bool isSubComponentized = message.Segments("PV1")[0].Fields(7).Components(1).IsSubComponentized;

OR

bool isSubComponentized = message.IsSubComponentized("PV1.7.1");

Update value of any component

message.Segments("PID")[0].Fields(5).Components(1).Value = "Jayant";

OR

message.setValue("PID.5.1", "Jayant");

Adding new Segment


//Create a Segment with name ZIB
Segment newSeg = new Segment("ZIB");
 
//Create Field ZIB_1
Field ZIB_1 = new Field("ZIB1");
//Create Field ZIB_5
Field ZIB_5 = new Field("ZIB5");
 
//Create Component ZIB.5.2
Component com1 = new Component("ZIB.5.2");
 
//Add Component ZIB.5.2 to Field ZIB_5
//2nd parameter here specifies the component position, if you want to insert segment on particular position
//If we don’t provide 2nd parameter, component will be inserted to next position (if field has 2 components this will be 3rd, if field is empty this will be 1st component
ZIB_5.AddNewComponent(com1, 2);
 
//Add Field ZIB_1 to segment ZIB, this will add a new filed to next field location, in this case first field
newSeg.AddNewField(ZIB_1);
 
//Add Field ZIB_5 to segment ZIB, this will add a new filed as 5th field of segment
newSeg.AddNewField(ZIB_5, 5);
 
//add segment ZIB to message
message.AddNewSegment(newSeg);

New Segment would look like this

ZIB|ZIB1||||^ZIB.5.2


After you have evaluated and modified required values you can again get the message in text format


String strUpdatedMsg = message.SerializeMessage();

Generate ACKs

AA ACK

String ackMsg = message.getACK();

To generate negative ACK message with error message


String ackMsg = message.getNACK("AR", "Invalid Processing ID");


This is my small library to parse HL7 messages.


I welcome any comments/criticism to help improve this.