web stats
Mirth Community - View Single Post - Mirth Tools: User defined functions
View Single Post
Old 04-19-2012, 06:50 AM
narupley's Avatar
narupley narupley is offline
Mirth Employee
Join Date: Oct 2010
Posts: 7,126
narupley is on a distinguished road

UPDATE: I've created a public GitHub repository to track these example channels, code templates, scripts, or whatever else!


To start with I only added the ones I wrote, because I didn't want to presume and add code from others without their explicit permission. Pull requests welcome!
UPDATE 2-13-13: Made a change so that segName can be a regular expression

Okay, this one might be helpful to some people....

getSegmentsAfter: Returns an array of segments with the specified name that come after a given segment in the message.

Say you have multiple OBR groups in your message. Sometimes you want to do something with only the OBXs that come after that particular OBR, and not necessarily all of the OBXs in the entire message. The same goes for NTEs after an OBX, etc. Assuming that you're not using the strict HAPI parser (most of us don't), this might be fairly tricky to do.

The getSegmentsAfter function does it for you. Given the root node (root), the segment you want to start at (startSeg), and the name of the segments you want to get (segName), this function will return an array of those segments.

There are two other optional parameters:
  • consecutiveInd: If this is true, then the segments to be collected are expected to come directly after the starting segment. If any segment is encountered that doesn't have a name of segName, collection is immediately stopped. If this is false, then collection is stopped when another segment of the same name as startSeg is encountered. For example, say you have the following message:
    If startSeg is the first OBR, segName is "OBX", and consecutiveInd is true, then getSegmentsAfter will return the first two OBXs in the message, but not the third one. If consecutiveInd is false, then it will return the first three OBXs, but not the fourth one.

  • stopSegNames: This is an array of segment names that you want to act as an "emergency brake" to stop collection. If one of these segments is encountered, then iteration is stopped. This is useful when, for example, you have a message like this:
    In HL7Land, the OBR segment contains two groups, the observation group (consisting of the first two OBXs) and the specimen group (consisting of the SPM and the third OBX). In this case you don't want to get consecutive OBXs because there may be NTEs/ZDSs in between, but on the other hand you don't want to include the OBX that is part of the specimen group. So if "SPM" is included in stopSegNames, then all will be good.

  • Get all OBXs after the first OBR segment:
  • Get all consecutive NTEs after the first OBX segment:
  • Get all OBXs after the first OBR segment, but don't include any OBXs in the SPM or ZBP groups:
  • Add a new NTE segment to the first OBR group (at the order level rather than the observation level):
    var newNTE = <NTE/>;
    newNTE['NTE.3']['NTE.3.1'] = 'whatever';
    var nteGroup = getSegmentsAfter(msg,msg.OBR[0],'NTE',true);
    if (nteGroup.length > 0)
         msg.children()[nteGroup[nteGroup.length-1].childIndex()] += newNTE;
         msg.OBR[0] += newNTE;
  • Reset all of the set IDs of the OBXs after every OBR in the message:
    for each (obr in msg.OBR) {
         var obxGroup = getSegmentsAfter(msg,obr,'OBX',false,['SPM','ZBP']);
         for (var i = 0; i <= obxGroup.length-1; i++)
              msg.children()[obxGroup[i].childIndex()]['OBX.1']['OBX.1.1'] = (i+1);
  • Get all Z-segments after each OBR segment:
    for each (obr in msg.OBR) {
    	for each (zseg in getSegmentsAfter(msg,obr,/Z[A-Z\d]{2}/)) {
    		// Do something

The code:

	Author: Nick Rupley
	Date Modified: 2/13/2013
	getSegmentsAfter: Returns an array of segments with the specified name that come after a given segment in the message.

			root:			The root HL7Message node of the message, or the parent of the segment node.
			startSeg:		The segment AFTER which to start collecting segments.
			segName:		The name (String or RegExp) of the segments you want to collect.

			consecutiveInd:	If true, indicates that the segments are expected to come directly after startSeg. 
					If false, segments are collected until another segment with the same name as startSeg is encountered.
					Defaults to false.
			stopSegNames:	An array of segment names that, when encountered, stop the collection of segments.

function getSegmentsAfter(root, startSeg, segName, consecutiveInd, stopSegNames) {
	function test(str) {
		return segName instanceof RegExp ? segName.test(str) : segName === str;

	// The index to start collection is the next one up from the starting segment
	var index = startSeg.childIndex()+1;
	// The return array
	var out = [];
	// Boolean placeholder to stop iteration
	var done = false;
	// Object that will contain all of the stopSegNames strings, bound to a truthy value (1)
	var stopNames = {};
	// Indicates whether we have any stop segments
	var stopNamesInd = false;
	// If stopSegNames is defined
	if (stopSegNames !== undefined && stopSegNames !== null) {
		// Set our indicator to true
		stopNamesInd = true;
		// Add each string in the array to our object
		for each (name in stopSegNames)
			stopNames[name] = 1;

	// Iterate through each child in the root, starting at the segment after startSeg, and
	// ending at the final segment, or when the done flag is set to true.
	while (index < root.children().length() && !done) {
		// If a stop segment is encountered, stop iteration
		if (stopNamesInd && root.children()[index].name().toString() in stopNames)
			done = true;
		// If a segment with the same name as startSeg is encountered, stop iteration
		else if (root.children()[index].name().toString() == startSeg.name().toString() && !consecutiveInd)
			done = true;
		// If we're only collecting consecutive segments and we encounter a segment with a name other than segName, stop iteration
		else if (!test(root.children()[index].name().toString()) && consecutiveInd)
			done = true;
		// If all previous tests passed, and the current segment has a name of segName, then add it to our array
		else if (test(root.children()[index].name().toString()))
		// Increment our index counter

	// Return the output array
	return out;
Attached Files
File Type: xml getSegmentsAfter.xml (3.0 KB, 427 views)
File Type: xml getSegmentsAfter (new 2-13-13).xml (3.1 KB, 803 views)

Last edited by narupley; 06-08-2018 at 10:35 AM.
Reply With Quote