Parsing EDI the better way

You’re parsing it the hard way.  But it’s not too late to fix it!

Welcome back!  By now you have the EDI basics down pat.   You know what ANSI X12 is all about, you know about segment structures, EDI envelopes, etc.  For HIPAA developers you may already be familiar with what EDI messages you’ll be sending and receiving.  For example 837, 835 and 834s.  Now you need to think of EDI development, the fun part.  If you’ve already done EDI development I’m here to tell you that 80% of developers have been doing this part the hard way.  Before you kill me let me explain.

The first part of getting EDI data into your systems is parsing it.  You probably bought a third party component that does this step for you.  It probably let’s you iterate over all the segments and elements via an array or list.  For example, let’s say we want to iterate over claims in an 837 EDI file and put them in a .Net DataTable.

 foreach (LightWeightLoop loop in claims)
 {
     LightWeightSegment subscriber = loop.GetSegment("SBR");
     LightWeightLoop subscriberInfo = loop.GetLoop("2010BA");
     LightWeightSegment subName = subscriberInfo.GetSegment("NM1");

     LightWeightLoop insuranceInfo = loop.GetLoop("2010BB");
     LightWeightSegment insuranceName = insuranceInfo.GetSegment("NM1");

     DataRow subInfoRow = subscriberTable.NewRow();
     subInfoRow[0] = rowNumber;
     subInfoRow[1] = subName.Elements[2].DataValue + " " + subName.Elements[3].DataValue;
     subInfoRow[2] = insuranceName.Elements[2].DataValue;
     subInfoRow[3] = subscriber.Elements[1].DataValue;
     subInfoRow[4] = subscriber.Elements[8].DataValue;

     subscriberTable.Rows.Add(subInfoRow);

     Collection<LightWeightLoop> claimLoop = loop.GetLoopCollection("2300");

     foreach (LightWeightLoop cl in claimLoop)
     {
        LightWeightSegment clm = cl.GetSegment("CLM");
        LightWeightSegment hi = cl.GetSegment("HI");

        DataRow claimInfoRow = claimsTable.NewRow();
        claimInfoRow[0] = rowNumber;
        claimInfoRow[1] = clm.Elements[0].DataValue;
        claimInfoRow[2] = clm.Elements[1].DataValue;
        claimInfoRow[3] = hi.Elements[0].Elements[1].DataValue;

        claimsTable.Rows.Add(claimInfoRow);

        Collection<LightWeightLoop> serviceLineLoops = cl.GetLoopCollection("2400");
        foreach (LightWeightLoop sl in serviceLineLoops)
        {
            //Get the service line segment
           LightWeightSegment sv1 = sl.GetSegment("SV1");

            DataRow serviceLineInfoRow = serviceLineTable.NewRow();
            serviceLineInfoRow[0] = rowNumber;
            serviceLineInfoRow[1] = sv1.Elements[0].Elements[1].DataValue;
            serviceLineInfoRow[2] = sv1.Elements[1].DataValue;
            serviceLineInfoRow[3] = sv1.Elements[3].DataValue;
            serviceLineInfoRow[4] = sv1.Elements[6].Elements[0].DataValue;

            serviceLineTable.Rows.Add(serviceLineInfoRow);
         }
    }

}

Notice that I need to intimately know about the all the elements of a segment.  For example let’s look a the CLM segment.  I need to know that element 1 of the segment is the Patient Control Number.  Or that element 2 of the SV1 segment is the Monetary Amount of the service line. Now imagine doing this for each segment in an EDI file.  You need to know everything about the segment’s elements in order to properly use the EDI data.  You need to know the meaning of each element!  THIS is what 80% of EDI developers struggle with.  This is time time-waster.  This is what makes EDI developers cringe.

Shouldn’t there be a better way to do this?  Shouldn’t that third party component do this for you?  Shouldn’t you get some sleep?  That answer to all of those questions is YES! Now enters a component called Typed Documents that support ALL 5010 HIPAA standards.  It does all this for you.   With Typed Documents developers don’t need intimately know the details of elements.  There is an actual object generated that knows this.  You just need to look for the property on that object.  EDI development is now well-structured and better.  You don’t need to fish around for data.  The following code demonstrates how to display 837 professional claims in a C# Dataset;

private void DisplayAllClaims(List<DocumentLoop> claims)
{
   int rowNumber = 1;
   foreach (DocumentLoop claimSection in claims)
   {
      SBR subscriber = claimSection.GetSegment<SBR>();
      DocumentLoop subscriberInfo = claimSection.GetLoop("2010BA");
      NM1 subName = subscriberInfo.GetSegment<NM1>();

      DocumentLoop insuranceInfoSection = claimSection.GetLoop("2010BB");
      NM1 insuranceName = insuranceInfoSection.GetSegment<NM1>();

      DataRow subInfoRow = subscriberTable.NewRow();
      subInfoRow[0] = rowNumber;
      subInfoRow[1] = subName.NameLastOrOrganizationName + " " + subName.FirstName;
      subInfoRow[2] = insuranceName.NameLastOrOrganizationName;
      subInfoRow[3] = subscriber.IndividualRelationshipCode;
      subInfoRow[4] = subscriber.ClaimFilingIndicatorCode;

      subscriberTable.Rows.Add(subInfoRow);

      List<DocumentLoop> claimLoopSections = claimSection.GetLoops("2300");
      foreach (DocumentLoop cl in claimLoopSections)
      {
         CLM clm = cl.GetSegment<CLM>();

         DataRow claimInfoRow = claimsTable.NewRow();
         claimInfoRow[0] = rowNumber;
         claimInfoRow[1] = clm.ClaimSubmitterIdentifier;
         claimInfoRow[2] = clm.MonetaryAmount;

         claimsTable.Rows.Add(claimInfoRow);

         List<DocumentLoop> serviceLineSections = cl.GetLoops("2400");
         foreach (DocumentLoop sl in serviceLineSections)
         {
            //Get the service line segment
            SV1 sv1 = sl.GetSegment<SV1>();

            DataRow serviceLineInfoRow = serviceLineTable.NewRow();
            serviceLineInfoRow[0] = rowNumber;
            serviceLineInfoRow[1] = sv1.CompositeMedicalProcedureIdentifier.ProductServiceID1;
            serviceLineInfoRow[2] = sv1.MonetaryAmount1;

            serviceLineTable.Rows.Add(serviceLineInfoRow);
          }
      }
     rowNumber++;
  }
}

Wasn’t that easy? With Typed Documents you can even create HIPAA EDI documents using typed data.  No more guessing or fishing for properties.  Now you know exactly what they are!  For example:

 private void CreateFile()
 {
     Typed5010Document sampleEDIFile = new Typed5010Document ();

     //Create an interchance loop. This loop will contain all other loops in the EDI structure
     DocumentLoop interchangeHeader = sampleEDIFile.MainSection.CreateLoop("Interchange Header");
                    
     //Create an ISA segment in the interchange loop
     ISA isa = interchangeHeader.CreateSegment<ISA>();
     isa.AuthorizationInformationQualifier = "00";
     isa.AuthorizationInformation = "";
     isa.SecurityInformationQualifier = "00";
     isa.SecurityInformation = "";
     isa.InterchangeIDQualifier1 = "ZZ";
     isa.InterchangeSenderID = "InterchangeSenderID";
     isa.InterchangeIDQualifier2 = "ZZ";
     isa.InterchangeReceiverID = "InterchangeReceiverID";
     isa.InterchangeDate = "150303";
     isa.InterchangeTime = "1804";
     isa.RepetitionSeparator = "^";
     isa.InterchangeControlVersionNumber = "00501";
     isa.InterchangeControlNumber = "1";
     isa.AcknowledgmentRequested = "1";
     isa.InterchangeUsageIndicator = "P";
     isa.ComponentElementSeparator = ":";

     //Now create the function header section
     DocumentLoop functionalHeader = interchangeHeader.CreateLoop("Functional Header");
     GS gs = functionalHeader.CreateSegment<GS>();
     gs.FunctionalIdentifierCode = "HC";
     gs.ApplicationSenderCode = "ApplicationSenderCode";
     gs.ApplicationReceiverCode = "ApplicationReceiverCode";
     gs.Date = "20150303";
     gs.Time = "1424";
     gs.GroupControlNumber = "1234";
     gs.ResponsibleAgencyCode = "X";
     gs.VersionReleaseIndustryIdentifierCode = "005010X222";
              
     //Create a transaction header loop
     DocumentLoop transactionHeader = functionalHeader.CreateLoop("Transaction Header");
     ST st = transactionHeader.CreateSegment<ST>();
     st.TransactionSetIdentifierCode = "837";
     st.TransactionSetControlNumber = "1";
     st.ImplementationConventionReference = "005010X222";

     //Add an BHT segment to the transaction header loop
     BHT bht = transactionHeader.CreateSegment<BHT>();
     bht.HierarchicalStructureCode = "0019";
     bht.TransactionSetPurposeCode = "00";
     bht.ReferenceIdentification = "44445";
     bht.Date = "20040213";
     bht.Time = "0345";

     //Create the end of the transaction (SE segment). This must be done in a loop.
     DocumentLoop endOfTransactionLoop = transactionHeader.CreateLoop("End Of Transaction");
     SE se = endOfTransactionLoop.CreateSegment<SE>();
     se.TransactionSetControlNumber = "1";
     se.NumberOfIncludedSegments = "3";

     //Create the end of the functional group (GE segment). This must be done in a loop.
     DocumentLoop endOfFunctionalGroupLoop = functionalHeader.CreateLoop("End Functional Group");
     GE ge = endOfFunctionalGroupLoop.CreateSegment<GE>();
     ge.GroupControlNumber = "11234";
     ge.NumberOfTransactionSetsIncluded = "1";

     //Finally create the end of the interchange loop (IEA segment). This must be done in a loop.
     DocumentLoop endInterchangeSection = interchangeHeader.CreateLoop("End Interchange");
     IEA iea = endInterchangeSection.CreateSegment<IEA>();
     iea.InterchangeControlNumber = "123";
     iea.NumberOfIncludedFunctionalGroups = "1";
      
     //Generate the EDI file
     string ediData= sampleEDIFile.ToEDIString(new Delimiters());

}

If you were doing it the old way you’re forgiven.  Now you know that there is a better way.

Take Charge Of EDI

RDPCrystal EDI Library

trial2