Skip to content
Jake Aitchison edited this page Jan 20, 2023 · 10 revisions

Decoding a message

var message = @"MSH|^~\&|CohieCentral|COHIE|Clinical Data Provider|TCH|20060228155525||QRY^R02^QRY_R02|1|P|2.3|QRD|20060228155525|R|I||||10^RD&Records&0126|38923^^^^^^^^&TCH|||";

var parser = new PipeParser();
var parsed = parser.Parse(message);
var qryR02 = parsed as QRY_R02;

Assert.IsNotNull(qryR02);
Assert.AreEqual("38923", qryR02.QRD.GetWhoSubjectFilter(0).IDNumber.Value);

Unexpected Segments

What happens if there is a segment in an HL7 message which is not expected? See below for some examples of what that means...

  • A segment appears in the message payload for a given message type i.e. ADT_A01 which is not defined in the specification for that message type.
  • A segment repeats which should not repeat (according to the specification)
  • A segment appears out of sequence (according to the HL7 specification segment sequence is important)
  • A non-standard segment appears in the message payload.

The example below shows a (non-standard) message payload for message type ADT_A01 and how to access the out of sequence segment data. In this message type the NK1 segments should come after the PID segment and before the PV1 segment (according to the V2.3 HL7 specification).

Instead of parsing these segments and inserting them into the existing (standard) group NK1 it creates a new (2nd) group and appends the occurrence of the group to the end of the group name NK1{group occurrence} i.e. the 2nd NK1 group would be called NK12 and a 3rd group would be NK13 and so on.

It does this because the parser has already moved on passed the original (standard) group and not found any NK1 segments to parse and will not make any assumptions about where the segment should go, especially when there are groups of repeatable segments such as Procedure or Insurance.

[Test]
public void Parse_V23_ADT_A01()
{
    var message =
        "MSH|^~\\&|V500|01010|TEST|TEST|20170130125848||ADT^A01|12345||2.3||||||8859/1\r"
        + "EVN|A01|20170130125600|||12345|20170130125600\r"
        + "PID|1|12345^^^PATIENT MASTER^MRN^|12345^^^PATIENT MASTER^MRN^||TEST||20101114|F||4|16 Bothar Na Tra^^Ireland^^^1101^home^^||||2303|1||12345^^^EPISODE NUMBER^FIN NBR^|12312312310||||||0|Not Known / Not Stated||1101||\r"
        + "PV1|1|I|TEST^08^011^A207^^Bed(s)^A207|01||^^^^^^|0121212J^Stephen^Peter^J^^Dr^^^Doctor Provider Number^Personnel^^^DOCUPIN^|||ONC|||1|01|||0121212J^Stephen^Peter^J^^Dr^^^Doctor Provider Number^Personnel^^^DOCUPIN^|8|12345^0^^^Visit Id|5M^20170130125600|||||||||||||||||||B2021||Active|||20170130125600\r"
        + "NK1|1||||0404111111^^^test@test.com||Proxy\r"
        + "NK1|2||||0404111112^^^test2@test.com||Proxy 2";

    var parser = new PipeParser();

    var adtA01 = (NHapi.Model.V23.Message.ADT_A01)parser.Parse(message);
    var allNextOfKin = adtA01.GetAll("NK12");

    Assert.IsNotNull(allNextOfKin);
    Assert.That(nextOfKinGroup2, Has.Count.EqualTo(2));
    Assert.AreEqual(
        "test@test.com",
        ((Model.V23.Segment.NK1)allNextOfKin[0]).GetPhoneNumber(0).EmailAddress.Value);
    Assert.AreEqual(
        "test2@test.com",
        ((Model.V23.Segment.NK1)allNextOfKin[1]).GetPhoneNumber(0).EmailAddress.Value);
}

What happens if the unexpected segments do not follow on from each other?

[Test]
public void Parse_V23_ADT_A01()
{
    var message =
        "MSH|^~\\&|V500|01010|TEST|TEST|20170130125848||ADT^A01|12345||2.3||||||8859/1\r"
        + "EVN|A01|20170130125600|||12345|20170130125600\r"
        + "PID|1|12345^^^PATIENT MASTER^MRN^|12345^^^PATIENT MASTER^MRN^||TEST||20101114|F||4|16 Bothar Na Tra^^Ireland^^^1101^home^^||||2303|1||12345^^^EPISODE NUMBER^FIN NBR^|12312312310||||||0|Not Known / Not Stated||1101||\r"
        + "PV1|1|I|TEST^08^011^A207^^Bed(s)^A207|01||^^^^^^|0121212J^Stephen^Peter^J^^Dr^^^Doctor Provider Number^Personnel^^^DOCUPIN^|||ONC|||1|01|||0121212J^Stephen^Peter^J^^Dr^^^Doctor Provider Number^Personnel^^^DOCUPIN^|8|12345^0^^^Visit Id|5M^20170130125600|||||||||||||||||||B2021||Active|||20170130125600\r"
        + "NK1|1||||0404111111^^^test@test.com||Proxy\r"
        + "IN1|0001|2|314000|||||||||19800101|||1|BARDOUN^LEA SACHA|1|19981201|AVENUE FRANC GOLD 8^^LUXEMBOURGH^^6780^150|||||||||||||||||\r"
        + "NK1|2||||0404111112^^^test2@test.com||Proxy 2";

    var parser = new PipeParser();

    var adtA01 = (NHapi.Model.V23.Message.ADT_A01)parser.Parse(message);
    var nextOfKinGroup2 = adtA01.GetAll("NK12");

    Assert.IsNotNull(nextOfKinGroup2);
    Assert.That(nextOfKinGroup2, Has.Count.EqualTo(1));
    Assert.AreEqual(
        "test@test.com",
        ((Model.V23.Segment.NK1)nextOfKinGroup2[0]).GetPhoneNumber(0).EmailAddress.Value);

    var nextOfKinGroup3 = adtA01.GetAll("NK13");

    Assert.IsNotNull(nextOfKinGroup2);
    Assert.That(nextOfKinGroup3, Has.Count.EqualTo(1));
    Assert.AreEqual(
        "test2@test.com",
        ((Model.V23.Segment.NK1)nextOfKinGroup3[0]).GetPhoneNumber(0).EmailAddress.Value);
}

Event Map to Code Structure Mappings

Some message types are not mapped to their exact same event type which can cause some confusion when you first encounter it.

For example, ADT^A01, ADT^A04, ADT^A08 and ADT^A13 event types will all be parsed into the ADT^01 structure.

The following unit test illustrates this behaviour:

[Test]
public void TestADTA04IsMappedAsA01()
{
    var hl7Data = @"MSH|^~\&|CohieCentral|COHIE|Clinical Data Provider|TCH|20060228155525||ADT^A04|1|P|2.5.1|
EVN|
PID|1|12345
PV1|1";

    var parser = new PipeParser();
    var msg = parser.Parse(hl7Data);

    Assert.IsNotNull(msg, "Message should not be null");
    var a04 = (ADT_A01)msg;

    Assert.AreEqual("A04", a04.MSH.MessageType.TriggerEvent.Value);
    Assert.AreEqual("1", a04.PID.SetIDPID.Value);
}

The Event to Structure Map for each version of HL7 supported can be found below: