예제 #1
0
        public void ShouldConvertFromASingleXCNElement()
        {
            HL7Message mesg = OBR1;
            var        xcn1 = mesg.Element("OBR.16").AsXCN();

            Assert.Equal("MCINTYRE", xcn1.FamilyName);
        }
예제 #2
0
        public void ShouldThrowExceptionForRepeatingXCNElement()
        {
            HL7Message mesg = OBR2;
            var        obr  = mesg.Element("OBR[1]");
            var        xcns = obr.IndexedElement(16);

            Assert.Throws <InvalidOperationException>(() => xcns.AsXCN());
        }
예제 #3
0
        public void PD1ReturnedForAnyLineEnding()
        {
            var CrLfPD1 = CrLfMsg.Element("PD1");
            var CrPD1   = CrMsg.Element("PD1");
            var LfPD1   = LfMsg.Element("PD1");

            Assert.Equal(CrPD1.ToString(), CrLfPD1.ToString());
            Assert.Equal(CrPD1.ToString(), LfPD1.ToString());
        }
예제 #4
0
        public void CRLineEndingsOBX64ReturnsWithEscapedCRLF()
        {
            HL7Message resultMsg = ExampleCRMessageWithB64;
            var        obx3      = resultMsg.Element("OBX[3]");
            string     obx3txt   = obx3;

            Assert.Contains("Clinical PDF Report MR077065T-1", (string)obx3);
            Assert.Contains(@"\X0D\\X0A\", obx3txt);
        }
예제 #5
0
        public void ShouldConvertDateRange()
        {
            var txt = MSH + PID1;


            var message = new HL7Message(txt);

            var firstAddress  = message.Element($"PID.11[1]");
            var firstFrom     = firstAddress[11].AsDateRange().DateFrom;
            var firstTo       = firstAddress[11].AsDateRange().DateTo;
            var secondAddress = message.Element($"PID.11[2]");
            var secondFrom    = secondAddress[11].AsDateRange().DateFrom;
            var secondTo      = secondAddress[11].AsDateRange().DateTo;

            Assert.Equal(new DateTime(2014, 04, 30, 12, 11, 10), firstFrom.Value);
            Assert.Equal(new DateTime(2020, 01, 31, 12, 10, 08), firstTo.Value);
            Assert.Equal(new DateTime(2015, 5, 30, 12, 11, 10), secondFrom.Value);
            Assert.False(secondTo.HasValue);
        }
예제 #6
0
        public void CRLFLineEndingsOBX64ReturnsWithEscapedCRLF()
        {
            var        crlfWithB64 = ExampleCRMessage.Replace("\r", "\r\n") + OBXBase64 + '\n';
            HL7Message resultMsg   = crlfWithB64;
            var        obx3        = resultMsg.Element("OBX[3]");
            string     obx3txt     = obx3;

            Assert.Contains("Clinical PDF Report MR077065T-1", (string)obx3);
            Assert.Contains(@"\X0D\\X0A\", obx3txt);
        }
예제 #7
0
        public void ShouldConvertToAIEnumerableForOneXCNElement()
        {
            HL7Message mesg    = OBR4;
            var        obr     = mesg.Element("OBR[1]");
            var        xcns    = obr.IndexedElement(16);
            var        xcnList = xcns.AsXCNs();

            Assert.Single(xcnList);
            Assert.Equal("Hooker", xcnList.FirstOrDefault().FamilyName);
            Assert.Equal("1620", xcnList.FirstOrDefault().ID);
        }
예제 #8
0
        public void ShouldConvertToAIEnumerableForRepeatingXCNElements()
        {
            HL7Message mesg    = OBR2;
            var        obr     = mesg.Element("OBR[1]");
            var        xcns    = obr.IndexedElement(16);
            var        xcnList = xcns.AsXCNs();

            Assert.Equal(2, xcnList.Count());
            Assert.Equal("MCINTYRE", xcnList.FirstOrDefault().FamilyName);
            Assert.Equal("McIntyre", xcnList.Skip(1).FirstOrDefault().FamilyName);
            Assert.Equal("1620", xcnList.Skip(1).FirstOrDefault().ID);
        }
예제 #9
0
        public void ShouldConvertIdentifier()
        {
            HL7Message message         = MSH + PID2;
            var        firstIdentifier = message.Element($"PID.3[1]");
            var        hl7Id           = firstIdentifier.AsCX();

            Assert.Equal("01", hl7Id.CheckDigit);
            Assert.Equal("IDCODE", hl7Id.CheckDigitScheme.Value);
            Assert.Equal("AUSIC", hl7Id.AssigningAuthority.NamespaceId.BestValue);
            Assert.Equal("NI", hl7Id.IdentifierTypeCode.BestValue);
            Assert.Equal("RMH", hl7Id.AssigningFacility.NamespaceId.BestValue);
            Assert.Equal(new DateTime(2020, 07, 01).ToUniversalTime(), hl7Id.EffectiveDate.Value.ToUniversalTime());
            Assert.Equal(new DateTime(2025, 07, 01).ToUniversalTime(), hl7Id.ExpirationDate.Value.ToUniversalTime());
        }
예제 #10
0
        public void ShouldExtractNumbersFromNM()
        {
            HL7Message mesg         = OBX3;
            var        obx          = mesg.Element("OBX[1]");
            var        valueElement = obx.IndexedElement(5);

            DataTypes.NM_Number number = valueElement;
            Assert.True(number.IsNumber);
            Assert.Equal(59, (int)number);
            Assert.Equal((Int64)59, number.AsInt64());
            Assert.Equal((float)59, number.AsFloat());
            Assert.Equal(59M, number.AsDecimal());
            Assert.Equal(59.0D, (double)number);
        }
예제 #11
0
        public void ShouldConvertASingleCE()
        {
            var message   = new HL7Message(OBX1);
            var OBXResult = message.Element("OBX[1].3");
            var hl7CE     = OBXResult.AsCE();

            //ClinicalPDFReport1^Clinical PDF Report MR077065T-1^^PDF^Display format in PDF^AUSPDI

            Assert.Equal("ClinicalPDFReport1", hl7CE.Identifier);
            Assert.Equal("Clinical PDF Report MR077065T-1", hl7CE.Text);
            Assert.Equal("", hl7CE.NameOfCodingSystem.Value);
            Assert.Equal("PDF", hl7CE.AlternateIdentifier);
            Assert.Equal("Display format in PDF", hl7CE.AlternateText);
            Assert.Equal("AUSPDI", hl7CE.NameOfAlternateCodingSystem.Value);
        }
예제 #12
0
        public void ShouldConvertED()
        {
            var txt = MSH + PID2 + OBR1 + OBX1;

            var message   = new HL7Message(txt);
            var OBXResult = message.Element("OBX[1].5");
            var hl7Ed     = OBXResult.AsED();

            //MIA^Image^PDF^Base64
            Assert.Equal("MIA", hl7Ed.SourceApplication.NamespaceId.BestValue);
            Assert.Equal("Image", hl7Ed.TypeOfData.BestValue);
            Assert.Equal("PDF", hl7Ed.DataSubType.BestValue);
            Assert.Equal("Base64", hl7Ed.Encoding.BestValue);
            Assert.StartsWith("JVBERi0xLjQKJeLjz9", hl7Ed.Data, StringComparison.InvariantCultureIgnoreCase);
        }
예제 #13
0
        public void ShouldConvertFromARepeatingXCNElement()
        {
            HL7Message mesg = OBR2;
            var        obr  = mesg.Element("OBR[1]");
            var        xcns = obr.IndexedElement(16);
            var        xcn1 = xcns[0].AsXCN();

            Assert.Equal("MCINTYRE", xcn1.FamilyName);
            Assert.Equal("0191324T", xcn1.ID);
            Assert.Equal("ANDREW", xcn1.GivenName);
            Assert.Empty(xcn1.SecondGivenNamesOrInitials);
            Assert.Equal("AUSHICPR", xcn1.AssigningAuthority.NamespaceId.BestValue);
            Assert.Equal("L", xcn1.NameTypeCode.BestValue);
            Assert.Equal("UPIN", xcn1.IdentifierTypeCode);
            var xcn2 = xcns[1].AsXCN();

            Assert.Equal("1620", xcn2.ID);
            Assert.Equal("McIntyre", xcn2.FamilyName);
        }
예제 #14
0
        public void ShouldConvertXADs()
        {
            //we need 5 altogether, but we dont have those defined, so we dont want to repeat.
            var tbleIds = new List <String>()
            {
                "0399", "0190", null, null, null
            };

            HL7Message mesg    = test1;
            var        address = mesg.Element("TTT[1].2").AsXAD(tbleIds, tables);

            Assert.Equal("0399", address.Country.TableId);
            Assert.Equal("0190", address.AddressType.TableId);
            Assert.Equal("H", address.AddressType.CodedValue);
            Assert.Equal("H", address.AddressType.Value);
            Assert.Equal("H", address.AddressType.BestValue);
            Assert.Equal("AUS", address.Country.CodedValue);
            Assert.Equal("AUS", address.Country.Value);
            Assert.Equal("AUS", address.Country.BestValue);
        }
예제 #15
0
        public void ShouldConvertXADs()
        {
            HL7Message mesg    = PID1;
            var        pid     = mesg.Element("PID[1]");
            var        addr    = pid.IndexedElement(11);
            var        xadList = addr.AsXADs();

            /*
             * 119 SMITH STREET^^SWANSEE^NSW^2281^AUS^H^^^^^20140430121110+1000&20200131121008+1100
             * 27 MANN AVENUE^^PATTERSON LAKES^NSW^3197^AUS^H^^^^^20150530121110+1000
             */

            Assert.Equal(2, xadList.Count());
            Assert.Equal("SWANSEE", xadList.FirstOrDefault().City);
            Assert.StartsWith("2014", xadList.FirstOrDefault().AddressValidityRange.ToString());
            Assert.Equal("AUS", xadList.Skip(1).FirstOrDefault().Country.BestValue);
            Assert.Equal("H", xadList.FirstOrDefault().AddressType.BestValue);
            Assert.Equal("2281", xadList.FirstOrDefault().ZipOrPostalCode);
            Assert.Equal("3197", xadList.Skip(1).FirstOrDefault().ZipOrPostalCode);
            Assert.Equal("27 MANN AVENUE", xadList.Skip(1).FirstOrDefault().StreetAddress.StreetOrMailingAddress);
        }
예제 #16
0
        public void ShouldReturnNullForFaultType()
        {
            var tbleIds = new List <String>()
            {
                "0399", "0190", null, null, null
            };

            HL7Message mesg    = test1;
            var        address = mesg.Element("TTT[1].2").AsXAD(tbleIds, tables);

            // force value to be wrong.
            address.AddressType.Value = "Q";
            address.Country.Value     = "ZZZ";
            Assert.Equal("0399", address.Country.TableId);
            Assert.Equal("0190", address.AddressType.TableId);
            Assert.Equal("", address.AddressType.CodedValue);
            Assert.Equal("Q", address.AddressType.Value);
            Assert.Equal("Q", address.AddressType.BestValue);
            Assert.Equal("", address.Country.CodedValue);
            Assert.Equal("ZZZ", address.Country.Value);
            Assert.Equal("ZZZ", address.Country.BestValue);
        }
예제 #17
0
        private static void AlternateMethodsForCreatingAHL7MessageObject(string msgText)
        {
            Console.WriteLine("\r\nCreating a HL7Message Object");
            Console.WriteLine("----------------------------");
            Console.WriteLine("Method 1 : Implicit cast: HL7Message mesg = msgText;");
            HL7Message mesgImplicit = msgText;

            // Alternatively = use an Explicit cast
            Console.WriteLine("Method 2 : Explicit cast: mesg = (HL7Message)msgText;");
            var mesgExplicit = (HL7Message)msgText;

            // OR simply use the constructor
            Console.WriteLine("Method 3 : Constructor: mesg = new HL7Message(msgText);");
            var mesgFromCtor = new HL7Message(msgText);

            // All Three methods produce the same result.
            Console.WriteLine("\r\nAll produce the same result:");
            Console.WriteLine($"TypeOf mesgImplicit {mesgImplicit.GetType()} - {mesgImplicit.Element("MSH")}");
            Console.WriteLine($"TypeOf mesgExplicit {mesgExplicit.GetType()} - {mesgExplicit.Element("MSH")}");
            Console.WriteLine($"TypeOf mesgfromCtor {mesgFromCtor.GetType()} - {mesgFromCtor.Element("MSH")}");
            Console.WriteLine();
        }
예제 #18
0
        public void ShouldConvertMultipleIdentifiers()
        {
            HL7Message message         = MSH + PID2;
            var        firstIdentifier = message.Element($"PID.3[]");
            var        hl7Ids          = firstIdentifier.AsCXs();
            var        id1             = hl7Ids.FirstOrDefault();
            var        id2             = hl7Ids.Skip(1).FirstOrDefault();
            var        id5             = hl7Ids.Skip(4).FirstOrDefault();

            /*
             * 8003608166690501^01^IDCODE^AUSIC&UID&UIDTYPE^NI^RMH^20200701000000+1000^20250701000000+1000
             * 3071D2942H^^^AUSLINK^AN
             * QPCA9034W^^^AUSDVA^DVG
             * 3071D2942H^^^AUSLINK^HC
             * 307111942HR^^^AUSLINK^PEN
             * 307111942HR^^^AUSLINK^SEN
             * 2428778132^^^AUSHIC&211&300^MC^RMH^20140430^2020
             */
            Assert.Equal("8003608166690501", id1.ID);
            Assert.Equal("01", id1.CheckDigit);
            Assert.Equal("IDCODE", id1.CheckDigitScheme.BestValue);
            Assert.Equal("AUSIC", id1.AssigningAuthority.NamespaceId.BestValue);
            Assert.Equal("NI", id1.IdentifierTypeCode.BestValue);
            Assert.Equal("RMH", id1.AssigningFacility.NamespaceId.BestValue);
            Assert.Equal(new DateTime(2020, 07, 01).ToUniversalTime(), id1.EffectiveDate.Value.ToUniversalTime());
            Assert.Equal(new DateTime(2025, 07, 01).ToUniversalTime(), id1.ExpirationDate.Value.ToUniversalTime());

            Assert.Equal("3071D2942H", id2.ID);
            Assert.Equal("", id2.CheckDigitScheme.BestValue);
            Assert.Equal("AUSLINK", id2.AssigningAuthority.NamespaceId.BestValue);
            Assert.Equal("AN", id2.IdentifierTypeCode.BestValue);
            Assert.Null(id2.AssigningFacility);

            Assert.Equal("307111942HR", id5.ID);
            Assert.Equal("AUSLINK", id5.AssigningAuthority.NamespaceId.BestValue);
            Assert.Equal("PEN", id5.IdentifierTypeCode.BestValue);
        }
예제 #19
0
        public void ShouldConvertMultipleCEs()
        {
            var message         = new HL7Message(OBR5);
            var reasonsForStudy = message.Element("OBR[1].31[]");
            var hl7CEs          = reasonsForStudy.AsCEs();
            var ce1             = hl7CEs.FirstOrDefault();
            var ce2             = hl7CEs.Skip(1).FirstOrDefault();

            //^Insurance Claim^^INS^Reason:Insurance^Local~INV1^Acute Disorder^

            Assert.Equal("", ce1.Identifier);
            Assert.Equal("Insurance Claim", ce1.Text);
            Assert.Equal("", ce1.NameOfCodingSystem.Value);
            Assert.Equal("INS", ce1.AlternateIdentifier);
            Assert.Equal("Reason:Insurance", ce1.AlternateText);
            Assert.Equal("Local", ce1.NameOfAlternateCodingSystem.Value);

            Assert.Equal("INV1", ce2.Identifier);
            Assert.Equal("Acute Disorder", ce2.Text);
            Assert.Equal("", ce2.NameOfCodingSystem.Value);
            Assert.Equal("", ce2.AlternateIdentifier);
            Assert.Equal("", ce2.AlternateText);
            Assert.Equal("", ce2.NameOfAlternateCodingSystem.Value);
        }
예제 #20
0
        static void Main(string[] args)
        {
            var msgText = @"MSH|^~\&|CERNER||PriorityHealth||20191020050600+1000||ORU^R01|Q479004375T431430612|P|2.3|" + "\r" +
                          @"PID|||001677980~212323112^^^AUTH^MR^TESTING||SMITH^CURTIS||19680219|M||||||||||929645156318|123456789|" + "\r" +
                          @"PD1||||1234567890^LAST^FIRST^M^^^^^NPI|" + "\r" +
                          @"OBR|1|341856649^HNAM_ORDERID|000002006326002362|648088^Basic Metabolic Panel|||20061122151600|||||||||1620^Hooker^Robert^L||||||20061122154733|||F|||||||||||20061122140000|" + "\r" +
                          @"OBX|1|NM|GLU^Glucose Lvl||59|mg/dL|65-99^65^99|L|||F|||20061122154733|" + "\r" +
                          @"OBX|2|NM|ALT^Alanine Aminotransferase||23|umol/L|2-20^65^1000|H|||F|||20061122154733|" + "\r" +
                          @"OBX|3|NM|8893-0^Pulse rate^LN^78564009^^SCT|1.9.2.1|70|bpm^^ISO+||N|||F|||201706071449+1000" + "\r";

            try
            {
                Console.WriteLine("How to use the HL7 Enumerator for Decoding HL7 Messages");
                Console.WriteLine("-------------------------------------------------------\r\n");

                // Dont want to process the whole message? Use the Parse Only Method to check fields before processing
                // Here is an example:
                UseParseOnlyToConfirmWeCanProcessTheMessage(msgText);
                Console.WriteLine("\r\nProcessing ORU Message " + HL7Message.ParseOnly(msgText, "MSH.10"));


                // Process the HL7 message by Creating a HL7 Message Object
                // NOTE: this will always succeed - an exception should never be thrown, so there is no need
                // to test for it.
                HL7Message mesg = msgText;

                // yes, it is that simple, but the method below implements some other syntax versions
                AlternateMethodsForCreatingAHL7MessageObject(msgText);

                // Extract a Single field - say for logging purposes
                // Use the Element property to extract ANY specific field/subfield OR Group of fields/subFields
                DisplayExtractingAnElementMessage();
                Console.WriteLine($"Message received from Sending system {mesg.Element("MSH.3")}");

                // Extract a Whole Segment
                Console.Write("\r\nOR a whole PD1 Segment :\r\n  ");
                Console.WriteLine(mesg.Element("PD1"));

                // Extract a Repeating Field
                Console.WriteLine("\r\nOR a SET of repeating Fields: eg PID.3[]");
                var c = 0;
                mesg.Element("PID.3[]").ForEach(id => Console.WriteLine($"Repitition {++c}: {id}"));

                // Use the ALLSegments property with LINQ to extract and manipulate any part/subpart of a message
                // as a Low Level HL7Element
                DisplayUsingLinq();
                Console.WriteLine("Eg Test Names: ");
                var OBXTestNames = mesg.AllSegments("OBX").Select(o => o.Element("*.3.2"));
                // Note the use of the "*" wildcard - avoids needing to specify the Segment level.

                // Use Implicit String Casting to Output any Element as a string.
                Console.WriteLine($"\r\nThe message contains {OBXTestNames.Count()} Test Results:");
                foreach (string testName in OBXTestNames)
                {
                    Console.WriteLine($"  {testName}");
                }

                // Use LINQ on ANY element at any level to iterate over sub elements
                Console.Write("\r\nUse LINQ at the Element (field/component) Level to get information\r\nEg:  ");
                var NonEmptyComponentsInPD1 =
                    mesg.Element("PD1.4").Where(f => !string.IsNullOrWhiteSpace(f));
                Console.WriteLine($"PID.3 has {(mesg.Element("PD1.4").Count)} components, and {NonEmptyComponentsInPD1.Count()} have data");
                foreach (var component in NonEmptyComponentsInPD1)
                {
                    Console.WriteLine($"  {component}");
                }

                // Use self defined Constants for field definitions to make your code cleaner.
                DisplayConstantsMessage();
                const string PatientFamilyName = "PID.5.1";
                const string PatientGivenName  = "PID.5.2";
                Console.WriteLine($"Patients Name is : {mesg.Element(PatientFamilyName)}, {mesg.Element(PatientGivenName)}.");

                DisplayDataTypesMessage();
                // Use the "HL7Types" Namespace Helpers to safely get Numbered Field Values from components
                // Remember that Element FIELDS are ZERO based but in Segments the Segment Name is 0 so the FIELD Numbers
                // still correspond to the HL7 field numbers.
                const int fldSequence = 1;
                const int fldDataType = 2;
                const int fldTestName = 3;
                const int fldValue    = 5;
                const int fldUnits    = 6;
                const int fldRefRange = 7;
                const int fldAbFlag   = 8;

                // BUT Components are numbered 0 to n (not 1 to n).
                const int cvTestName = 1;
                const int cvTestCode = 0;

                // Now use our defintions to extract using Data Type primitives ElementValue and IndexedElement
                Console.WriteLine("\r\nUse Safe Element Options to Output only the Numeric test Results:\r\n");
                mesg.AllSegments("OBX")                                                               // Test Segments
                .Where(o => o.ElementValue(fldDataType).Equals("NM"))                                 // numeric fields
                .Select(o => $"{o.ElementValue(fldSequence),2}. " +
                        $"{o.IndexedElement(fldTestName).ElementValue(cvTestName),-30} " +            // test name
                        $"({o.IndexedElement(fldTestName).ElementValue(cvTestCode),-6}) " +           // test code
                        $"{o.IndexedElement(fldValue),6} " +                                          // test value
                        $"{o.IndexedElement(fldUnits).ElementValue(0),-6} " +                         // units
                        $"({o.IndexedElement(fldRefRange).ElementValue(0),-6}) " +                    // Range first field
                        $"{(o.ElementValue(fldAbFlag).Equals("N") ? "" : o.ElementValue(fldAbFlag))}" // Abflag
                        ).ToList()
                .ForEach(testResult => Console.WriteLine($"  {testResult}"));

                // Use the HL7 Data Type
                DisplayCommonDataTypes();

                // Use the DataType Extensions for Strict Typing of known Data Types.
                Console.WriteLine("\r\nUse A Common Data type to Extract Type safe properties");
                Console.WriteLine("Eg: PID.5 (Patient Name) is an XPN DataType (often repeating)");
                var ptName = mesg.Element("PID.5").AsXPN();
                // note, in this case it is ok AsXPN() because we know there is only 1 replicate.
                // for repeating fields, use AsXPNs() to return an IEnumerable of XPN
                Console.WriteLine($"Patients Name is : {ptName.FamilyName}, {ptName.GivenName}.");

                // Using a CX Data Type for repeating fields..
                var ids        = mesg.Element("PID.3[]");
                var patientIds = ids.AsCXs();
                // we know from the spec, that PID.3 is a replicating field of CX 's.  The included AsCXs method is
                // a simple extension method returning a CX_CompositeId type (supporting the IHL7Type interface).
                // If the include CX datatype is not suitable for your purpose, it is very easy to make your own.
                // Just Implement the HL7Type interface using the low level methods.
                //
                // NOTE: if you ask for a simple CX for a Replicating field, you will get a DEBUG exception indicating
                // that you should use an Enumerable type for this field

                Console.WriteLine($"Found {patientIds?.Count()} Ids using DataType Assigment");
                foreach (var cx in patientIds)
                {
                    // remember that certain elements in a CX MAY be null.
                    Console.WriteLine($"ID:       {cx?.ID}");
                    Console.WriteLine($"  IDType:   {cx?.IdentifierTypeCode}");
                    Console.WriteLine($"  Authority:{cx?.AssigningAuthority?.NamespaceId?.BestValue}");
                    Console.WriteLine($"  Facility: {cx?.AssigningFacility?.NamespaceId?.BestValue}");
                }

                /// One Alternative in the case where no type has been defined,
                /// you can use the low level elements OR Self Element references to extract the data
                Console.WriteLine($" Found {ids.Count} Ids Using Elements (low level)");
                foreach (var id in ids)
                {
                    if (id.Count > 0)
                    {
                        Console.WriteLine($"ID: {id[0]}");
                    }
                    else
                    {
                        Console.WriteLine($"ID: {id}"); // implict string casting
                    }
                    if (id.Count > 4)
                    {
                        Console.WriteLine($"  IDType:{id[4]}");
                    }
                    if (id.Count > 3)
                    {
                        Console.WriteLine($"  Issuer:{id[3]}");
                    }
                }

                /// HOWEVER - it is better to define your own Custom Type.
                /// See the Custom Data Types example in this repository.
                DisplayCustomDataTypesMessage();

                // Data Type Support.
                DisplayHL7TablesMessage();

                // Coded Values have 3 propertes. Value, CodedValue and Best Value.
                // Use the Property 'BestValue' in most cases for display as it returns either Value
                // or Coded Value depending on whether a table is attached and the value is known in the table.
                // When no table is defined for the Coded Value will always be empty
                var pt1IdTypeCode = patientIds.Skip(1).First().IdentifierTypeCode;
                Console.WriteLine("\r\nIdentifier Properties: with NO table attached.");
                Console.WriteLine($" Value      (Unvalidated)   : {pt1IdTypeCode.Value}");
                Console.WriteLine($" CodedValue (Validated)     : {pt1IdTypeCode.CodedValue}");
                Console.WriteLine($" BestValue  (Coded Or Value): {pt1IdTypeCode.BestValue}");
                Console.WriteLine($" Description                : {pt1IdTypeCode.Description}");
                Console.WriteLine($" Notes                      : {pt1IdTypeCode.Notes?.First()}...");

                // Attach manually created Table to CX we just read.
                // Manually Create a Data Table into In-Memory Provider
                Console.WriteLine("\r\nManually Create Tables to validate the properties");
                var tables = ManuallyCreateTablesIntoAInMemoryProvider();
                pt1IdTypeCode.Table = tables.GetCodeTable("0203");

                Console.WriteLine("\r\nIdentifier Properties: with table 0203 attached.");
                Console.WriteLine($" Value      (Unvalidated)   : {pt1IdTypeCode.Value}");
                Console.WriteLine($" CodedValue (Validated)     : {pt1IdTypeCode.CodedValue}");
                Console.WriteLine($" BestValue  (Coded Or Value): {pt1IdTypeCode.BestValue}");
                Console.WriteLine($" Description                : {pt1IdTypeCode.Description}");
                Console.WriteLine($" Notes                      : {pt1IdTypeCode.Notes.First()}...");

                // Automatically Attach suitable tables to the Data type as we read Assign it.
                // Assuming we hav the required tables, each datatype consists of a set of
                // Identifiers where data might be coded.
                DisplayAutomaticDataTableAssignment();

                // First Use a Table Provider as a source of tables.
                // The File Provider can access any table in a folder by TableID is very useful for this purpose
                var HL7TablesFolder = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6),
                    "ExampleTables");
                Console.WriteLine($"The process is: First, Get an instance of a table provider");
                Console.WriteLine("Eg: The 'FolderDataTableProvider'");

                var tablesFromFolder = new FolderDataTableProvider(HL7TablesFolder);
                Console.WriteLine($"Using tables in folder:{tablesFromFolder.Folder}");

                Console.WriteLine("Next, Look at the DataType (eg CX) to determine the number of Coded Elements in total");
                Console.WriteLine($"A CX data has {CX_CompositeId.TotalCodedFieldCount} Coded elements. I need a List of corresponding table names");

                // You will need 1 table reference for each Coded Item, in exact order that they will be constructed.
                Console.WriteLine("Add Required Table names to a String List IN Constructor Order\r\n");
                var tableIds = new List <string>();
                tableIds.Add("0061"); // CX_CompositeId.CheckDigitScheme needs table 0061 (we dont have that, but include it anyway)
                tableIds.Add("0363"); // CX_CompositeId.AssigningAuthority.NamespaceId needs table 0363
                tableIds.Add("0301"); // CX_CompositeId.AssigningAuthority.UniversalIDType needs table 0301
                tableIds.Add("0203"); // CX_CompositeId.IdentifierTypeCode needs table 0203
                tableIds.Add("");     // CX_CompositeId.AssigningFacility.NamespaceId needs some unknown table - leave it blank.
                tableIds.Add("0301"); // CX_CompositeId.AssigningFacility.UniversalIDType needs 0301 again (include it again)

                Console.WriteLine("Table Ids required for PID.5 (CX)");
                tableIds.ForEach(t => Console.WriteLine($"  {t}"));

                var validatedPatientIds = ids.AsCXs(tableIds, tablesFromFolder);
                c = 0;
                validatedPatientIds.ToList().ForEach(id =>
                {
                    Console.WriteLine($"\r\nID {++c} {id.ID}");
                    var bestValue   = id.CheckDigitScheme?.BestValue;
                    var isValid     = (id.CheckDigitScheme == null) ? "" : (id.CheckDigitScheme.IsValid.Value) ? "Yes" : "No";
                    var description = id.CheckDigitScheme.Description;
                    Console.WriteLine($"  CheckDigitScheme                  : {bestValue,7} Valid: {isValid} {description}");

                    bestValue   = id.AssigningAuthority?.NamespaceId.BestValue;
                    isValid     = (id.AssigningAuthority?.NamespaceId == null) ? "" : (id.AssigningAuthority.NamespaceId.IsValid.Value) ? "Yes" : "No";
                    description = id.AssigningAuthority?.NamespaceId.Description;
                    Console.WriteLine($"  AssigningAuthority.NamespaceId    : {bestValue,7} Valid: {isValid} {description}");

                    bestValue   = id.AssigningAuthority?.UniversalIdType.BestValue;
                    isValid     = (id.AssigningAuthority?.UniversalIdType == null) ? "" : (id.AssigningAuthority.UniversalIdType.IsValid.Value) ? "Yes" : "No";
                    description = id.AssigningAuthority?.UniversalIdType.Description;
                    Console.WriteLine($"  AssigningAuthority.UniversalIdType: {bestValue,7} Valid: {isValid} {description}");

                    bestValue   = id.IdentifierTypeCode?.BestValue;
                    isValid     = (id.IdentifierTypeCode == null) ? "" : (id.IdentifierTypeCode.IsValid.Value) ? "Yes" : "No";
                    description = id.IdentifierTypeCode?.Description;
                    Console.WriteLine($"  IdentifierTypeCode                : {bestValue,7} Valid: {isValid} {description}");

                    bestValue   = id.AssigningFacility?.NamespaceId.BestValue;
                    isValid     = (id.AssigningFacility?.NamespaceId == null) ? "" : (id.AssigningFacility.NamespaceId.IsValid.Value) ? "Yes" : "No";
                    description = id.AssigningFacility?.NamespaceId.Description;
                    Console.WriteLine($"  AssigningFacility.NamespaceId     : {bestValue,7} Valid: {isValid} {description}");

                    bestValue   = id.AssigningFacility?.UniversalIdType?.BestValue;
                    isValid     = (id.AssigningFacility?.UniversalIdType == null) ? "" : (id.AssigningFacility.UniversalIdType.IsValid.Value) ? "Yes" : "No";
                    description = id.AssigningFacility?.UniversalIdType?.Description;
                    Console.WriteLine($"  AssigningFacility.UniversalIdType : {bestValue,7} Valid: {isValid} {description}");
                }
                                                     );

                DisplayTimeAndNumericConversion();
                var ptDOB    = "PID.7";
                var mesgTime = "MSH.7";

                var dob    = mesg.Element(ptDOB);
                var mesgTs = mesg.Element(mesgTime);

                DisplayAsDateTimeInformation();
                Console.WriteLine($"DOB.AsDateTime() {mesg.Element(ptDOB)} does not have Timezone, so assume Local");
                Console.WriteLine($"  {dob.AsDateTime()} = {dob.AsDateTime().Value.ToString("o")}");
                Console.WriteLine($"msgTs.AsDateTime() {mesg.Element(mesgTime)} has Time Timezone. Stored as UTC.");
                Console.WriteLine($"  {mesgTs.AsDateTime()} = {mesgTs.AsDateTime().Value.ToString("o")}");


                DisplayAsLocalDateTimeInformation();
                Console.WriteLine($"DOB {mesg.Element(ptDOB)} No timezone, so display Current LOCAL");
                Console.WriteLine($"  {dob.AsLocalTime()} = {dob.AsLocalTime().Value.ToString("o")}");
                Console.WriteLine($"msgTime {mesg.Element(mesgTime)} Has TimeZone Shows in Current local");
                Console.WriteLine($"  {mesgTs.AsLocalTime()} = {mesgTs.AsLocalTime().Value.ToString("o")}");

                DisplayAsUTCDateTimeInformation();
                Console.WriteLine($"DOB {mesg.Element(ptDOB)} No Timezone, So safe to assume local to you");
                Console.WriteLine($"  {dob.AsUTCTime()} = {dob.AsUTCTime().Value.ToString("o")}");
                Console.WriteLine($"DOB {mesg.Element(ptDOB)} No Timezone, but can be forced to UTC.");
                Console.WriteLine($"  {dob.AsDateTime(DateTimeStyles.AssumeUniversal).Value.ToString("o")}");
                Console.WriteLine($"msgTime {mesg.Element(mesgTime)} is converted to UTC Time.");
                Console.WriteLine($"  {mesgTs.AsUTCTime()} = {mesgTs.AsUTCTime().Value.ToString("o")}");

                // NM_Numeric data Type supports implicity, explicit and has  As<Type> Methods.
                DisplayNumericConversion();
                const string ResultValue = "OBX[1].5";

                // Examples:
                var    result1      = mesg.Element(ResultValue).AsNM();
                int    nmAsInt      = result1.AsInteger();
                var    nmAsFloat    = result1.AsFloat();
                double nmAsdouble   = result1;
                var    nmAsCurrency = (decimal)result1;
                Console.WriteLine($"Result 1 ToString() {result1}");
                Console.WriteLine($"Result 1 {nmAsInt.GetType().Name} value {nmAsInt}");
                Console.WriteLine($"Result 1 {nmAsFloat.GetType().Name} value {nmAsFloat:0.0}");
                Console.WriteLine($"Result 1 {nmAsdouble.GetType().Name} value {nmAsdouble:0.00000000}");
                Console.WriteLine($"Result 1 {nmAsCurrency.GetType().Name} value {nmAsCurrency:0.00}");


                DisplayComposingMessages();

                // Compose a Segment
                Console.WriteLine("\r\n Composing a Segment using DataTypes");
                // Composed PID: PID||1234567^4^M11^ADT01^MR^University Hospital|1234567^4^M11^ADT01^MR^University Hospital~8003608833357361^^^AUSHIC^NI^
                var patientIdentifiers = new List <CX_CompositeId>()
                {
                    new CX_CompositeId()
                    {
                        ID                 = "1234567",
                        CheckDigit         = "4",
                        CheckDigitScheme   = "M11",
                        AssigningAuthority = new HD_HierarchicDesignator()
                        {
                            NamespaceId = "ADT01"
                        },
                        IdentifierTypeCode = "MR",
                        AssigningFacility  = new HD_HierarchicDesignator()
                        {
                            NamespaceId = "University Hospital"
                        }
                    },
                    new CX_CompositeId()
                    {
                        ID = "8003608833357361",
                        AssigningAuthority = new HD_HierarchicDesignator()
                        {
                            NamespaceId = "AUSHIC"
                        },
                        IdentifierTypeCode = "NI"
                    }
                };



                // Compose a PID
                var pid = new HL7Segment("PID");
                pid.SetField(2, patientIdentifiers.First());
                pid.SetField(3, patientIdentifiers.AsElement());

                Console.WriteLine("\r\nComposed PID: " + pid);
            }
            catch (Exception e)
            {
                Console.WriteLine("Unexpected exception : {0}", e.Message);
            }

            Console.ReadLine();
        }