Parse HL7 EDI Message using C# and NHAPI

NHAPI provides core components for parsing/encoding HL7 messages.In my case I will use NHapi.Model.V231 for parsing.I will be using below message to parse int his blog.

MSH|^~\&|ADL Messaging|ADL|Receiving App|Receiving facility|201907160346||ORU^R01|20190716033149_CM796136|T|2.3.1|||AL|||||
PID|||||SURNAME^FIRSTNAME^^^||189912310000|M|||^^^^|||||||||||||||||||
PV1|||Hsp^Hospital Ltd|||||||||||||||||||||||||||||||||||||||||
ORC|RE|PatientId|0019T637146||CM||||201907160346|||||||||||
OBR|1|CM796136|0019T637146|FBCX^FULL BLOOD COUNT^WinPath||201907151657|201907151030|||||||||^||||||||TDL|F||||||||||||||||||||
NTE|1||Morning hours 6-10am : 166-507 nmol/L..br\Afternoon hours 4-8pm : 73.8-291 nmol/L.
NTE|1||Morning1 hours 6-10am : 166-507 nmol/L..br\Afternoon hours 4-8pm : 73.8-291 nmol/L.
OBX|1|NM|HBGL^HAEMOGLOBIN (g/L)^WinPath^HAEMATOLOGY^1^0||122|g/L|130 - 170|L|||F|||||
NTE|1||Morning hours 6-10am : 166-507 nmol/L..br\Afternoon hours 4-8pm : 73.8-291 nmol/L.

Install the NHAPI in to your project.

The first thing I have done is I have extract the Identifier from this message, In my scenario I will be extracting it from ORC and PID segment depending up on the vendors I will be receiving the message file.

Birthdate of a patient can be extracted from PID segment like this

Now moving towards the main part we need to extract observation details from this message for this I have crated the two model classes (Patient Order and Patient Order Result) in which I will be storing the Observation details.

Here is the complete code snippet of my project.

using NHapi.Base.Parser;
using NHapi.Model.V231.Message;
using System;
using System.Collections.Generic;
using System.Linq;
using NHapi.Base.Model;
using NHapi.Model.V231.Segment;

namespace DemoHL7
{
    class Program
    {
        static void Main(string[] args)
        {
            string message = System.IO.File.ReadAllText(@"C:\Users\abdul.sami\Desktop\HL7Message.txt");
            PipeParser parser = new PipeParser();
            IMessage m = parser.Parse(message);
            ORU_R01 oRU_R01 = m as ORU_R01;

            string patientId = "";

            //Patient Identifier from ORC 2.1
            var EntityIdentifier = oRU_R01.GetPATIENT_RESULT().ORDER_OBSERVATIONs.FirstOrDefault().ORC.PlacerOrderNumber.EntityIdentifier;
            if (EntityIdentifier != null)
            {
                patientId = EntityIdentifier.Value;
            }
            else
            {
                //In Some Scenario Patient Identifier can also be extract from PID 3.1
                var PatientIdentifier = oRU_R01.GetPATIENT_RESULT().PATIENT.PID.GetPatientIdentifierList();
                if (PatientIdentifier != null)
                {
                    patientId = PatientIdentifier.FirstOrDefault() != null ? PatientIdentifier.FirstOrDefault().ID.Value : "";
                }
            }

            //BirthDate of a Patient can be extract from PID 7.1
            if (oRU_R01.GetPATIENT_RESULT().PATIENT.PID.DateTimeOfBirth.TimeOfAnEvent != null)
            {
                var timeOfAnEvent = oRU_R01.GetPATIENT_RESULT().PATIENT.PID.DateTimeOfBirth.TimeOfAnEvent;
                if (timeOfAnEvent.Year > 0 && timeOfAnEvent.Month > 0 && timeOfAnEvent.Day > 0)
                {

                    DateTime birthDate = new DateTime(timeOfAnEvent.Year, timeOfAnEvent.Month, timeOfAnEvent.Day, timeOfAnEvent.Hour, timeOfAnEvent.Minute, timeOfAnEvent.Second);

                }
            }
            List PatientOrderList = new List();
            foreach (var observation in oRU_R01.PATIENT_RESULTs.FirstOrDefault().ORDER_OBSERVATIONs)
            {
                List PatientOrderResultList = new List();
                PatientOrder PatientOrder = new PatientOrder();

                var OBR_UniversalServiceID = observation.OBR.UniversalServiceID;
                PatientOrder.LabTest = OBR_UniversalServiceID.Identifier != null ? OBR_UniversalServiceID.Identifier.Value : ""; //OBR 4.1
                PatientOrder.LabTestDescription = OBR_UniversalServiceID.Text != null ? OBR_UniversalServiceID.Text.Value : ""; //OBR 4.2
                PatientOrder.ResultStatus = observation.OBR.ResultStatus.Value;  //OBR 25.1
                if (observation.OBR.SpecimenReceivedDateTime.TimeOfAnEvent != null)
                {
                    var timeOfAnEvent = observation.OBR.SpecimenReceivedDateTime.TimeOfAnEvent; //OBR 14.1
                    if (timeOfAnEvent.Year > 0)
                    {
                        DateTime dateTime = new DateTime(timeOfAnEvent.Year, timeOfAnEvent.Month, timeOfAnEvent.Day, timeOfAnEvent.Hour, timeOfAnEvent.Minute, timeOfAnEvent.Second);
                        PatientOrder.SpecimenDateTime = dateTime;
                    }
                }
                if (observation.NTEs.Count() > 0)
                {
                    PatientOrder.Comments = GenerateNTEComments(observation.NTEs.ToList());  //Comments of OBR Segment currently I'm storing these(multiple) comments in single line(come seprated)
                }
                foreach (var observationDetail in observation.OBSERVATIONs)
                {
                    PatientOrderResult PatientOrderResult = new PatientOrderResult();
                    Varies result = observationDetail.OBX.GetObservationValue(0); //Observation Result
                    if (observationDetail.NTEs.Count() > 0)
                    {
                        PatientOrderResult.Comments = GenerateNTEComments(observationDetail.NTEs.ToList()); //Comments of OBX Segment currently I'm storing these(multiple) comments in single line(come seprated)
                    }
                    PatientOrderResult.Code = observationDetail.OBX.ObservationIdentifier.Identifier.Value; //Result Code OBX 3.1
                    PatientOrderResult.Description = observationDetail.OBX.ObservationIdentifier.Text.Value; //Result Code Description  OBX 3.2
                    PatientOrderResult.Result = result.Data.ToString();    // Result of a test OBX 5.1                    
                    PatientOrderResult.Unit = observationDetail.OBX.Units.Identifier != null ? observationDetail.OBX.Units.Identifier.Value : ""; //Unit OBX 6.1
                    PatientOrderResult.Ranges = observationDetail.OBX.ReferencesRange.Value; // OBX 7.1
                    PatientOrderResult.AbnormalFlag = observationDetail.OBX.GetAbnormalFlags(0).Value; // OBX 8.1
                    PatientOrderResult.ObservationResultStatus = observationDetail.OBX.ObservationResultStatus.Value;  //Observation Result Status OBX 11.1

                    PatientOrderResultList.Add(PatientOrderResult);
                }
                PatientOrder.PatientOrderResultList = PatientOrderResultList;
                PatientOrderList.Add(PatientOrder);

            }


        }
        public static string GenerateNTEComments(List nte)
        {
            string nteComment = "";
            try
            {
                for (int i = 0; i <= nte.Count() - 1; i++)
                {
                    if (nte[i].GetComment() != null && nte[i].GetComment().FirstOrDefault() != null && nte[i].GetComment().FirstOrDefault().Value != null)
                    {
                        if (nteComment != "")
                        {
                            nteComment += ", ";

                        }
                        nteComment += nte[i].GetComment().FirstOrDefault().Value;
                    }
                }
            }
            catch (Exception ex)
            {

            }
            return nteComment;
        }
    }

    public class PatientOrder
    {

        public string LabTest { get; set; }
        public string LabTestDescription { get; set; }
        public string ResultStatus { get; set; }
        public string Comments { get; set; }
        public DateTime? SpecimenDateTime { get; set; }
        public List PatientOrderResultList { get; set; }
    }
    public class PatientOrderResult
    {

        public string Code { get; set; }
        public string Description { get; set; }
        public string Result { get; set; }
        public string Unit { get; set; }
        public string Comments { get; set; }
        public string Ranges { get; set; }
        public string AbnormalFlag { get; set; }
        public string ObservationResultStatus { get; set; }
    }
}

Summary

In this blog I have tried to explain the parsing of HL7 message and highlighted the important fields in this message. 

2 thoughts on “Parse HL7 EDI Message using C# and NHAPI

  1. Pankaj's avatar Pankaj October 17, 2020 / 10:27 am

    Hello. I was trying to parse the HL7 message and get basic patient details first. But for me, oRU_R01 in `ORU_R01 oRU_R01 = m as ORU_R01;` is always null. I checked and found that it’s null even when I try to cast it to others like ADT_A01.
    Any lead would be highly appreciated.

    Like

    • Pierre Viau's avatar Pierre Viau May 3, 2021 / 8:17 pm

      In my case I to set this:
      IMessage m = parser.Parse(message,”2.4″);

      Like

Leave a reply to Pankaj Cancel reply