Basic Parsing
Parsing converts an HL7 message string into a structured Java object that you can navigate programmatically. The parser automatically detects the message version from MSH-12 and creates the appropriate typed message object. After parsing, you can use instanceof to determine the message type and cast to the specific class for type-safe access to segments. Always wrap parsing in try-catch blocks since malformed messages will throw HL7Exception.
import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.v25.message.ADT_A01;
import ca.uhn.hl7v2.model.v25.segment.MSH;
import ca.uhn.hl7v2.model.v25.segment.PID;
import ca.uhn.hl7v2.parser.Parser;
public class ParseMessageExample {
public static void main(String[] args) {
String hl7Message =
"MSH|^~\\&|SENDING_APP|SENDING_FACILITY|RECEIVING_APP|RECEIVING_FACILITY|20231117120000||ADT^A01|MSG00001|P|2.5\r" +
"EVN|A01|20231117120000\r" +
"PID|1||123456^^^HOSPITAL^MR||DOE^JOHN^A||19800115|M|||123 MAIN ST^^CITY^ST^12345^USA||(555)555-5555|||S||123456789\r" +
"PV1|1|I|2000^2012^01||||004777^SMITH^JOHN^^^DR|||SUR||||ADM|A0|\r";
try {
HapiContext context = new DefaultHapiContext();
Parser parser = context.getPipeParser();
// Parse the message
Message message = parser.parse(hl7Message);
// Determine message type
System.out.println("Message Type: " + message.getName());
// Cast to specific message type
if (message instanceof ADT_A01) {
ADT_A01 adtMessage = (ADT_A01) message;
// Access MSH segment
MSH msh = adtMessage.getMSH();
System.out.println("Sending Application: " +
msh.getSendingApplication().getNamespaceID().getValue());
System.out.println("Sending Facility: " +
msh.getSendingFacility().getNamespaceID().getValue());
System.out.println("Message Control ID: " +
msh.getMessageControlID().getValue());
System.out.println("Message Date/Time: " +
msh.getDateTimeOfMessage().getTime().getValue());
// Access PID segment
PID pid = adtMessage.getPID();
System.out.println("\nPatient Information:");
System.out.println("Patient ID: " +
pid.getPatientIdentifierList(0).getIDNumber().getValue());
System.out.println("Patient Name: " +
pid.getPatientName(0).getFamilyName().getSurname().getValue() + ", " +
pid.getPatientName(0).getGivenName().getValue());
System.out.println("Date of Birth: " +
pid.getDateTimeOfBirth().getTime().getValue());
System.out.println("Gender: " +
pid.getAdministrativeSex().getValue());
System.out.println("Address: " +
pid.getPatientAddress(0).getStreetAddress()
.getStreetOrMailingAddress().getValue() + ", " +
pid.getPatientAddress(0).getCity().getValue() + ", " +
pid.getPatientAddress(0).getStateOrProvince().getValue() + " " +
pid.getPatientAddress(0).getZipOrPostalCode().getValue());
}
context.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Parsing Lab Results (ORU^R01)
Lab result messages contain nested groups that require careful navigation. The PATIENT_RESULT group contains patient information and one or more ORDER_OBSERVATION groups. Each ORDER_OBSERVATION contains an OBR segment describing the test panel and multiple OBSERVATION groups with individual OBX results. Use the getReps() methods to determine how many repetitions exist at each level before iterating through results.
import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.v25.message.ORU_R01;
import ca.uhn.hl7v2.model.v25.segment.OBX;
import ca.uhn.hl7v2.model.v25.group.ORU_R01_ORDER_OBSERVATION;
import ca.uhn.hl7v2.model.v25.group.ORU_R01_PATIENT_RESULT;
import ca.uhn.hl7v2.parser.Parser;
public class ParseLabResultsExample {
public static void main(String[] args) {
String hl7Message =
"MSH|^~\\&|LAB|HOSPITAL|RECEIVER|HOSPITAL|20231117140000||ORU^R01|MSG00005|P|2.5\r" +
"PID|1||123456^^^HOSPITAL^MR||DOE^JOHN^A||19800115|M\r" +
"OBR|1|ORD123456||CBC^COMPLETE BLOOD COUNT^LOCAL|||20231117120000|||||||20231117140000|||004777^SMITH^JOHN^^^DR\r" +
"OBX|1|NM|WBC^White Blood Count^LOCAL||7.5|10*3/uL|4.5-11.0|N|||F\r" +
"OBX|2|NM|RBC^Red Blood Count^LOCAL||4.8|10*6/uL|4.5-5.5|N|||F\r" +
"OBX|3|NM|HGB^Hemoglobin^LOCAL||14.5|g/dL|13.5-17.5|N|||F\r" +
"OBX|4|NM|HCT^Hematocrit^LOCAL||43.2|%|41-53|N|||F\r";
try {
HapiContext context = new DefaultHapiContext();
Parser parser = context.getPipeParser();
Message message = parser.parse(hl7Message);
if (message instanceof ORU_R01) {
ORU_R01 oruMessage = (ORU_R01) message;
System.out.println("Lab Results Message");
System.out.println("===================\n");
// Get patient result
ORU_R01_PATIENT_RESULT patientResult = oruMessage.getPATIENT_RESULT();
// Patient info
String patientId = patientResult.getPATIENT().getPID()
.getPatientIdentifierList(0).getIDNumber().getValue();
String patientName = patientResult.getPATIENT().getPID()
.getPatientName(0).getFamilyName().getSurname().getValue() + ", " +
patientResult.getPATIENT().getPID()
.getPatientName(0).getGivenName().getValue();
System.out.println("Patient: " + patientName + " (ID: " + patientId + ")\n");
// Get order observation
ORU_R01_ORDER_OBSERVATION orderObs =
patientResult.getORDER_OBSERVATION();
// Test info
String testCode = orderObs.getOBR().getUniversalServiceIdentifier()
.getIdentifier().getValue();
String testName = orderObs.getOBR().getUniversalServiceIdentifier()
.getText().getValue();
System.out.println("Test: " + testName + " (" + testCode + ")\n");
System.out.println("Results:");
System.out.println("--------");
// Iterate through observations
int numObs = orderObs.getOBSERVATIONReps();
for (int i = 0; i < numObs; i++) {
OBX obx = orderObs.getOBSERVATION(i).getOBX();
String obsCode = obx.getObservationIdentifier()
.getIdentifier().getValue();
String obsName = obx.getObservationIdentifier()
.getText().getValue();
String obsValue = obx.getObservationValue(0).getData().toString();
String obsUnits = obx.getUnits().getIdentifier().getValue();
String refRange = obx.getReferencesRange().getValue();
String abnormalFlag = obx.getAbnormalFlags(0).getValue();
System.out.printf("%s (%s): %s %s [Reference: %s] %s\n",
obsName, obsCode, obsValue, obsUnits, refRange,
abnormalFlag.equals("N") ? "" : "ABNORMAL");
}
}
context.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Generic Parsing (Version-Independent)
When you need to handle messages of any HL7 version without version-specific code, use the Terser utility class. Terser provides path-based access to message elements using string expressions like ”/.MSH-9-1” for the message type. This approach is especially useful when building generic message routers, transformers, or when the message version is unknown at compile time. The trade-off is less compile-time type safety compared to version-specific classes.
import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.model.Message;
import ca.uhn.hl7v2.model.Segment;
import ca.uhn.hl7v2.model.Type;
import ca.uhn.hl7v2.parser.Parser;
import ca.uhn.hl7v2.util.Terser;
public class GenericParseExample {
public static void main(String[] args) {
String hl7Message =
"MSH|^~\\&|SENDING_APP|SENDING_FACILITY|RECEIVING_APP|RECEIVING_FACILITY|20231117120000||ADT^A01|MSG00001|P|2.5\r" +
"PID|1||123456^^^HOSPITAL^MR||DOE^JOHN^A||19800115|M\r";
try {
HapiContext context = new DefaultHapiContext();
Parser parser = context.getGenericParser(); // Can parse any version
Message message = parser.parse(hl7Message);
// Use Terser for path-based access
Terser terser = new Terser(message);
System.out.println("Generic Parsing using Terser:");
System.out.println("Message Type: " + terser.get("/.MSH-9-1"));
System.out.println("Trigger Event: " + terser.get("/.MSH-9-2"));
System.out.println("Sending Application: " + terser.get("/.MSH-3-1"));
System.out.println("Patient ID: " + terser.get("/.PID-3-1"));
System.out.println("Patient Family Name: " + terser.get("/.PID-5-1-1"));
System.out.println("Patient Given Name: " + terser.get("/.PID-5-2"));
System.out.println("Patient DOB: " + terser.get("/.PID-7-1"));
System.out.println("Patient Gender: " + terser.get("/.PID-8"));
context.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}