How to use Hapi Terser with HL7

Hapi terser is the easiest way to extract and set data in a HL7 v2 messages. In the next example, I will show how to:

  • Create a Terser form a String message
  • Extract information from simple fields, components and repetitions
  • Set data in any part of the message

First of all, I have created an HL7 Message version 2.3, which I will be using in all the tests. The message is very simple, contains all the Patient details in the PID segment, 2 Nexts of Kin in the NKX segment, and patient visit information in the PV1 segment. The MSH segment contains metadata like the version of the message (2.3) and the type of the Message ADT A01, which is an admission message.

public class TerserTest {

    Message message;

    Terser terser;

    @Before
    public void setup() throws Exception{
        String m = "MSH|^~\\&|hl7Integration|hl7Integration|||||ADT^A01|||2.3|\r" +
                "EVN|A01|20130617154644\r" +
                "PID|1|465 306 5961||407623|Wood^Patrick^^^MR||19700101|1|||High Street^^Oxford^^Ox1 4DP~George St^^Oxford^^Ox1 5AP|||||||\r" +
                "NK1|1|Wood^John^^^MR|Father||999-9999\r"+
                "NK1|2|Jones^Georgie^^^MSS|MOTHER||999-9999\r"+
                "PV1|1||Location||||||||||||||||261938_6_201306171546|||||||||||||||||||||||||20130617134644|||||||||";


        //Parse the message
        PipeParser pipeParser = new PipeParser();
        this.message = pipeParser.parse(m);
        this.terser = new Terser(message);
    }


Note that I have used the “\r” special character to set the end of line. The Hapi parser doesn’t recognized the “\n” character.

Once we have parsed the message and built a Terser, accessing each field it is straightforward. If we would like to access a simple field, we need to use the terser object and specify the segment and field, like: terser.get(“/segment-field”).

@Test
    public void testAccessSimpleFields() throws Exception{

        //Patient Id
        assertEquals("465 306 5961", terser.get("/PID-2"));
        //Dob
        assertEquals("19700101", terser.get("/PID-7"));
        //Patient Surname
        assertEquals("Wood", terser.get("/PID-5-1"));
        //Patient First Name
        assertEquals("Patrick", terser.get("/PID-5-2"));
    }

We can get a specific components using the ‘-’ character. For instance the PID-5-2, is the second component of the fifth field.
    @Test
    public void testAccessSegmentRepetitions() throws Exception{

        //First Next of Kin Id
        assertEquals("1", terser.get("NK1(0)-1"));

        //Second Next of Kin Id
        assertEquals("2", terser.get("NK1(1)-1"));
    }

We can get particular repetitions using the brackets. Depending where we put the brackets we will be retrieving a segment repetition, a field repetition or a component repetition.
    @Test
    public void testAccessFieldRepetitions() throws Exception{
        //Primary Address: Street
        assertEquals("High Street", terser.get("/PID-11(0)-1"));
        //Primary Address: PostCode
        assertEquals("Ox1 4DP", terser.get("/PID-11(0)-5"));
        //Secondary Address: Street
        assertEquals("George St", terser.get("/PID-11(1)-1"));
        //Secondary Address: PostCode
        assertEquals("Ox1 5AP", terser.get("/PID-11(1)-5"));
    }


Also we can use the Terser to add or update a field. In this case we will need to use the set method and add the field or component and the new value, like: terser.set(“/segment-field-component”, “new value”).
    @Test
    public void testUpdateSimpleFields() throws Exception{
        //Update Patient Id
        terser.set("/PID-2", "123456");
        assertEquals("123456", terser.get("/PID-2"));

        //Update Dob
        terser.set("/PID-7", "19800101");
        assertEquals("19800101", terser.get("/PID-7"));
    }

    @Test
    public void testSetComponents() throws Exception{
        //Patient Surname
        terser.set("/PID-5-1", "Jones");
        assertEquals("Jones", terser.get("/PID-5-1"));

    }

    @Test
    public void testSetTypeFields() throws Exception{
        //Add a secondary address
        terser.set("/PID-11(1)-1", "Wellington Avenue");
        assertEquals("Wellington Avenue", terser.get("/PID-11(1)-1"));
    }


Some people prefers to get/set the data using the Hapi methods instead of the terser. For instance, If you want to retrieve the date of birth instead of using terser.get(“PID-7″), you can use pid.getDateOfBirth().getTimeOfAnEvent().getValue().From my point of view this approach presents some disadvantages:
– Hapi methods forces a specific version of HL7 to be used.
– In real life, clients not always follow the standard and you can find that they are populating information in a field that doesn’t correspond to the standard specification. This could be confusing for other developers working within the project.

That’s why I always recommend to use Hapi terser.

If you would like to see how to set repetitions in an HL7 message, please visit:

How to set repetitions in HL7 messages using HAPI Terser

You can find the whole project in github.

You may also like...

5 Responses

  1. alex shaw says:

    Not working

    OBR
    OBX|1|TX
    NTE|1|L
    OBX|40|
    NTE|1|L
    NTE|2|L

    var NTE1 = terser.Get(“/.OBSERVATION(0)/.NTE1-1”);
    var NTE2 = terser.Get(“/.OBSERVATION(0)/.NTE1-2”);

  2. raise says:

    Hi,
    is there a way to extract the VN out of PID3 directly? (Without iterating)

    PID|1||D-95353^^^^PI~D-55353^^^^VN||PLASTNAME^PFIRSTNAME^^^^^L||19900101|M||U^Unknown|123 MAIN RD^^CITY^NJ^12345^USA^M

    Thx

  3. Adam says:

    Hi,

    If we have multiple NTE messages with the same numbers is there a way to locate them?

    My second question: When I try to locate OBX|5| it also fails. Is it because there is NTE in between and is there a way to avoid this?

    OBX|1|ST|CHROM21^Chromosome 21||Negative||||||F|||20180531115104|
    OBX|2|ST|CHROM18^Chromosome 18||Negative||||||F|||20180531115104|
    OBX|3|ST|CHROM13^Chromosome 13||Negative||||||F|||20180531115104|
    OBX|4|ST|INTERP1^Interpretation||See Notes||||||F|||20180531115104|
    NTE|1||This specimen showed an expected representation of
    NTE|2||chromosome 21, 18 and 13 material. Clinical correlation is
    NTE|3||suggested.
    OBX|5|ST|CHROMY^Y Chromosome||Detected||||||F|||20180531115104|
    OBX|6|ST|YINTERP^Y Chr. Interpretation||Consistent with a male fetus.||||||F|||20180531115104|
    OBX|7|ST|AF^Additional Findings||N/A||||||F|||20180531115104|
    OBX|8|ST|AFINTERP^Add’l Findings Interp||N/A||||||F|||20180531115104|
    OBX|9|ST|AFNOTE^Add’l Findings Note||N/A||||||F|||20180531115104|
    OBX|10|ST|Lab Director Comments||See Notes||||||F|||20180531115104|
    NTE|1||Fetal Fraction: 15%

  4. RS says:

    Hi How can i get number of segments in a message

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.