Tuesday 28 May 2013

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;  
   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");  
 Segment IN1 = message.Segments("IN1")[0];  

Accessing Fields

Access field values
 String SendingFacility = message.getValue("MSH.4");  
 String SendingFacility = message.DefaultSegment("MSH").Fields(4).Value;  
 String SendingFacility = message.Segments("MSH")[0].Fields(4).Value;  

Check if field is componentized
 bool isComponentized = message.Segments("PID")[0].Fields(5).IsComponentized;  
 bool isComponentized = message.IsComponentized("PID.5");  

Check if field has repetitions
 bool isRepeated = message.Segments("PID")[0].Fields(3).HasRepetitions;  
 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
 List<Field> repList = message.Segments("PID")[0].Fields(3).Repetitions();  

Update value of any field i.e. to update PV1.2 – patient class
 message.setValue("PV1.2", "I");  
 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");  
 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;  
 bool isSubComponentized = message.IsSubComponentized("PV1.7.1");  

Update value of any component
 message.Segments("PID")[0].Fields(5).Components(1).Value = "Jayant";  
 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  
 //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  

New Segment would look like this

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

 String strUpdatedMsg = message.SerializeMessage();  

Generate ACKs
 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.

Sample Immunization Records Blockchain using Hyperledger Composer

This is basic and sample Blockchain implementation of Immunization Records using Hyperledger Composer.  Source Code available at:  https...