Skip to content

Unpacking a Packed Delimited Field

Some source systems pack several values into one field, with a second delimiter separating each value from its label. The field below holds two procedures, each a comma-separated list of CPT codes followed by a hyphen and a description:

99213, 99214-Office visit, established patient
80053, 80054-Metabolic panel, comprehensive

The comma cannot be the row separator here, because it also appears inside the code list and inside the description. Only one delimiter in a packed field is safe to split on: the one that never occurs in the data. Split on that delimiter, then split each row once at the first occurrence of the inner delimiter.

// The line feed separates procedures. Commas occur inside both the code list
// and the description, so they are left alone.
var packed = source.getNode('/procedures/[1]/code');
var rows = StringUtils.splitByWholeSeparator(packed, '\n');
var rowIndex = 1;

for (var i = 0; i < rows.length; i++) {
    var row = StringUtils.trim(rows[i]);
    if (!StringUtils.contains(row, '-')) {
        continue;
    }
    message.setNode('/procedures/[' + rowIndex + ']/code',
        StringUtils.trim(StringUtils.substringBefore(row, '-')));
    message.setNode('/procedures/[' + rowIndex + ']/description',
        StringUtils.trim(StringUtils.substringAfter(row, '-')));
    rowIndex++;
}

substringBefore and substringAfter cut at the first hyphen, which keeps any later hyphen with the description. rowIndex counts output elements rather than input rows, so a skipped row leaves no gap in the array. See Writing to Arrays for the rule that limits the array index.

Handling Both Line Ending Styles

A packed field from a Windows sender carries \r\n rather than \n. Replace the carriage return before splitting:

var rows = StringUtils.splitByWholeSeparator(StringUtils.replace(packed, '\r', '\n'), '\n');

splitByWholeSeparator treats adjacent separators as one separator, so the pair of line feeds produced from \r\n does not create a blank row.

When the Inner Delimiter Is Missing

substringBefore returns the whole input string when the separator is not found, and substringAfter returns an empty string. A row with no hyphen therefore yields a code with a blank description rather than an error. The loop above skips those rows instead. Decide which the interface needs: skipping drops data silently, while writing the row with a blank description keeps it visible downstream.

Replacing the Field in Place

Where the packed value lives in the message being modified rather than in the source, read it into a variable first, then remove the original element so the rebuilt array starts empty:

var packed = message.getNode('/procedures/[1]/code');
message.removeFirstNode('/procedures/[1]');

The loop then writes /procedures/[1], /procedures/[2], and so on, with no leftover element holding the original packed string.

Writing to Other Formats

For CSV output, use the column name as the node path and the row counter as the instance, as in Converting a JSON Array to a CSV Message. For one repeating HL7 segment per row, see Converting a JSON Array to Repeating HL7 Segments.