On this page:

20.6HL7 v2.x Mapping API

 

The JavaScript execution API can be used to manipulate HL7 v2.x messages. This is typically done in conjunction with the HL7 v2.x Endpoint modules.

When working with HL7 v2.x messages, the message object may be treated as a special kind of Map where the map key corresponds to a path within the message.

For example, the following examples show getting and setting values from an HL7 v2.x message.

// This variable holds the actual HL7 v2.x message
var rawMsg = theMessage.rawMessage;

// Retrieve a value
var messageType = rawMsg['MSH-9-1'];
// Set a value
rawMsg['PID-5[2]-1'] = 'Jones';

Path Syntax: Repetitions

For any element that is repeatable (i.e. segments and fields), you may add [n] at the item, where n is 0-indexed. If this is omitted, the first repetition is implied. For example:

  • OBX refers to the first OBX segment in the message
  • OBX[0] refers to the first OBX segment in the message
  • OBX[2] refers to the third OBX segment in the message
  • OBX[1]-5[1] refers to the second repetition of OBX-5 within the second OBX segment in the message

Path Syntax: Fields, Components, and Subcomponents

Field/Component/Subcomponent numbers are referred to using their field number. These numbers are 1-indexed, so the first field of the PID segment is called PID-1. This often seems confusing at first, but it is done this way to align with the way these items are historically named.

Some fields in HL7 v2.x will have components (a further division within a field) and some components will have subcomponents (a further division still). There is no level of division lower than a subcomponent.

For example:

  • PID-11-1-2 refers to the 11th field of PID (Patient Address), in the first component (Street Address), in the second subcomponent (Street Name).

Path Syntax: Groups

Many HL7 v2.x structures are organized into segment groups, which are collections of segments that can be repeated as a group.

For example, see the ORU_R01 message structure. In this example, the OBX segments are nested several group levels below the message level.

The following examples show two ways of accessing an OBX segment:

  • */OBX refers to a recursive search for the first OBX segment found anywhere in the message
  • */OBX[1] refers to a recursive search for the second OBX segment found anywhere in the message
  • /PATIENT_RESULT/ORDER_OBSERVATION/OBSERVATION/OBX refers to an explicit lookup of the OBX segment within a specific path

20.6.1Repetitions

 

Many Groups, Segments, and Fields in HL7 v2.x are considered repeatable, meaning that they have a maximum cardinality of more than 1.

The path syntax listed above can be used to get/set repetitions of repeatable elements. For example:

rawMsg['PID-5[0]-1'] = 'Smith';      // Set the value
var lastName = rawMsg['PID-5[0]-1']; // Get the value

Function: getRepetitionCount()

It is also possible to use the getRepetitionCount() function to access the current number of repetitions in a repeatable element. For example:

// Add repetition to the end
var repCount = rawMsg['PID-5'].getRepetitionCount();
rawMsg['PID-5[' + repCount + ']'] = 'Smith';

This function can also be used at the segment level:

var count = rawMsg['NTE'].getRepetitionCount();

20.6.2Structure Interrogation

 

Different message structures consist of different groups and segments. For example, an ADT_A01 message structure includes a PROCEDURE group and ROL segments whereas an ADT_A09 message structure does not. The following method can be used to interrogate a given message's structure at runtime.

Function: hasChild(name)

The hasChild(name) function can be invoked at the message and group levels, and it can be used to interrogate the structure of a given message or group. The name argument should identify either a group or segment. This function returns true if the named child exists in the structure; otherwise it returns false.

For example:

// Message-level interrogation
// rawMsg is an ADT_A01
rawMsg.hasChild('PROCEDURE'); // returns true
rawMsg.hasChild('ROL'); // returns true
}
// Message-level interrogation
// rawMsg is an ADT_A09
rawMsg.hasChild('PROCEDURE'); // returns false
rawMsg.hasChild('ROL'); // returns false
}
// Group-level interrogation
// rawMsg is an ORU_R01
rawMsg['/PATIENT_RESULT'].hasChild('ORDER_OBSERVATION'); // returns true
rawMsg['/PATIENT_RESULT/ORDER_OBSERVATION'].hasChild('OBR') // returns true
}
// Group-level interrogation
// rawMsg is an ORU_R01
rawMsg['/PATIENT_RESULT'].hasChild('PROCEDURE'); // returns false
rawMsg['/PATIENT_RESULT/ORDER_OBSERVATION'].hasChild('PR1') // returns false
}

20.6.3Content Clearing

 

In addition to accessing and populating various parts of a message, this content can also be cleared.

Function: clear()

The clear() function can be invoked at the segment, field, component, and sub-component levels.

For example:

rawMsg['PID-5-1-1'].clear(); // clears the value in this sub-component
rawMsg['PID-5-1'].clear();   // clears the value in this component, including the values in any sub-components
rawMsg['PID-5'].clear();     // clears the values in all components and sub-components in this field
rawMsg['PID'].clear();       // clears all values in this segment

20.6.4Content Interrogation

 

Simply because a given message structure includes a group, segment, or field does not mean that this element is populated with a value. For example, an ADT_A01 message structure includes a PID segment; however, it may be prudent to ensure PID-13 (Phone Number - Home) is populated with a value before attempting to process it. The following method can be used to interrogate a given message's content at runtime.

Function: isEmpty()

The isEmpty() function can be invoked at the group, segment, and field levels. This function returns false if a value is populated; otherwise it returns true.

For example:

if (rawMsg['PID-13'].isEmpty()) {
   Log.warn('New phone, who dis?');
}

20.6.5Parsing Raw Field Values

 

By default, values being passed in will be treated as literal strings and will be escaped as necessary. For example, consider the following code:

rawMsg['PID-5'] = 'Smith^John';

In the example above, the ^ character is escaped. If this should be interpreted as raw HL7 v2.x code, you can use the parse(String) method instead, as shown below:

rawMsg['PID-5'].parse('Smith^John');

You can also use the parse() function with repetition separators to parse multiple repetitions of a field. For example:

rawMsg['PID-5'].parse('Smith^John~Smith^Johnnie');

20.6.6Encoding

 

The encode() function can be invoked at the message, segment, and field levels. This function returns an encoded string of the populated value.

This function is commonly used in conjunction with the parse() function when copying populated values from one part of a message to another during translation and conversion. For example, one could easily copy all of the component values of the second repetition of PID-3 into the first repetition as follows:

rawMsg['PID-3[0]'].parse(rawMsg['PID-3[1]'].encode());

This is particularly useful when massaging a message prior translation and conversion. Consider a message that populates components with "" for empty strings. These can easily be removed from the entire message as follows:

rawMsg.parse(rawMsg.encode().replace(/""/g, ''));

20.6.7The Hl7V2 Object

 

The Hl7V2 object provides utility methods that are useful when working with HL7 v2.x messaging.

Function: newMessage(messageCode, messageTriggerEvent, processingId)

The newMessage(messageCode, messageTriggerEvent, processingId) function can be used to create a new message.

Parameters

This function takes the following parameters:

  • messageCode – This parameter is a string that identifies MSH-9.1 (Message Code) of the new message (e.g. ADT, RAS, etc.).

  • messageTriggerEvent – This parameter is a string that identifies MSH-9.2 (Trigger Event) of the new message (e.g. A01, O17, etc.).

  • processingId – This parameter is a string that identifies MSH-11 (Processing ID) of the new message (e.g. T for testing, P for production, etc.).

Output

This function returns an HL7 v2.x Message, which is the same type as Hl7V2ReceivedMessage.rawMessage.

Example: Converting Message Structures

A good use case would be an incoming HL7 v2.x feed that includes DFT_P03 messages sent to an HL7 v2.x Listening Endpoint module that expects RAS_O17 messages. A callback script with the function onPreConvertHl7V2ToFhir(theMessage, theConversionResult) could make use of the Hl7V2 object to create a new RAS_O17 message, then populate it with values from the original DFT_P03 message.

/**
 * This function will be called any time that a new message is received
 *
 * @param theMessage          The received HL7 v2.x message details
 * @param theConversionResult The result of an HL7 v2.x message runtime mapping
 */
function onPreConvertHl7V2ToFhir(theMessage, theConversionResult) {

	/*
	 * This variable holds the actual HL7 v2.x message
	 * In this case, it is a DFT_P03 message
	 */
	var rawMsg = theMessage.rawMessage;
	
	// Create a new RAS_O17 message
	var newMsg = Hl7V2.newMessage('RAS', 'O17', String(rawMsg['MSH-11']));
	
	// Replace the original message with the new message
	theMessage.rawMessage = newMsg;
	
	// Populate the new message as appropriate
	newMsg['MSH-1'] = rawMsg['MSH-1'];
	newMsg['MSH-2'] = rawMsg['MSH-2'];
	...
}

Functions: new*(message)

The new*(message) functions return a new, unpopulated object of an HL7 v2.x datatype.

The following functions are available:

Function Returns
newCE(message) Coded Element
newCWE(message) Coded with Exceptions
newDT(message) Date
newFT(message) Formatted Text Data
newNM(message) Numeric
newSN(message) Structured Numeric
newST(message) String Data
newTM(message) Time
newTS(message) Timestamp
newTX(message) Text Data

If there is an HL7 v2.x datatype that you would like to see supported, let us know!

Parameters

These functions take the following parameter:

Output

These functions return a new, unpopulated object of the specified HL7 v2.x datatype.

Example: Creating a New CWE Object

A new, unpopulated CWE (Coded with Exceptions) can be easily created as follows:

var cwe = Hl7V2.newCWE(rawMsg);

The CWE can then be populated as usual:

cwe['CWE-1'] = '123456';
cwe['CWE-1'] = 'Fancy!';
cwe['CWE-3'] = 'http://example.org/code';

20.6.8Working with Variable Datatypes

 

Some HL7 v2.x fields, components, and sub-components allow for variable datatypes. For example, OBX-5 (Observation Value) can be populated with a variety of datatypes, as identified by the value in OBX-2 (Value Type). In such cases, it is necessary to populate the element with an explicit datatype. This is accomplished using the Hl7V2.new*(message) functions in conjunction with the setData(object) function.

Function setData(object)

The setData(object) function works at the field, component, and sub-component levels where such an element allows for variable HL7 v2.x datatypes.

Parameters

This function takes the following parameters:

  • object – A JavaScript object of an HL7 v2.x datatype.

Output

This function does not currently return a value, and any returned value will be ignored.

Example: Populating OBX-5 with a Structured Numeric

OBX-5 (Observation Value) can be populated with an SN (Structured Numeric) as follows:

// Create the SN
var sn = Hl7V2.newSN(rawMsg);

// Populate the SN (|^100^-^200|, i.e. equal to range of 100 through 200)
sn['SN-2'] = '100';
sn['SN-3'] = '-';
sn['SN-4'] = '200';

// Populate OBX-5 (Observation Value) with the SN
rawMsg['PATIENT_RESULT/ORDER_OBSERVATION/OBSERVATION/OBX-5'].setData(sn);

20.6.9Working with Z-Segments

 

In order to add a Z-Segment to a message, use the following form:

var zzz = rawMsg.addSegment('ZZZ');
zzz['ZZZ-1'] = 'FIELD1';
zzz['ZZZ-2'] = 'FIELD2';