admin管理员组

文章数量:1296316

I used Mirth about 10 years ago and realize I have forgotten pretty much everything and a lot of my resources are no longer available. I am looking to iterate through OBR and OBX segments to pull the OBR 4.2, 7.1, 16.2 to be used as a section header and OBX 3.2, 5.1, 7.1 fields to show below on the report.

Basically take this:

MSH|^~\&|LAB|LIS||EMR|202107201651||ORU^R01|082017045701|P|2.3|| |NE|NE
PID|1||M1302^^^MR||TEST^PATIENT^T^^||19670101|M 123 8th street^apt.22b^long beach^CA^90802^||(714)555-1212|(714)222-5555|873lfif|4441113|
PV1|1|O|RGH^^^RGH^^^^|999999^TEST^TEST^^^^^L|288^ALBRIGHT^MD^^^^^L ||V4735|201008201648|
ORC|RE||15175288^ALBRIGHT^MD^^^^^L|
OBR|1||15175|CBC^COMPLETE BLOOD COUNT^L|R|202107200800|202107200800BB^RGH^^^^^^ ^^^^^^RGH|201008201648|B|288^ALBRIGHT^MD^^^^^L| ||20100820170246F|^||100.0||G A
OBX|1|NM|WBC^WBC^L||4.0|10\S\3/MM\S\3|3.6-11.1|F202107200759|RGH|ADM
OBX|2|NM|RBC^RBC^L||5.0|10\S\6/MM\S\3|4.50-5.90|F202107200758|RGH|ADM
OBX|3|NM|HGB^HGB^L||12.5|g/dL|12.0-18.0|F202107200757|RGH|ADM
ORC|RE||15175288^ALBRIGHT^MD^^^^^L|
OBR|2||15175|ALC^ALCOHOL,ETHYL^L|R|202107201650|20 1008201648BB^RGH^^^^^^^^^^^^RGH|201008201648 |B|288^ALBRIGHT^MD^^^^^L20100820170246F|^ |GA
OBX|1|NM|ALC^ALCOHOL (ETHANOL)^L||36|mg/dL|0-32|HF201008201650|RGH|ADM

and make:

CBC 202107260800 ALBRIGHT
WBC 4.0 3.6-11.1
RBC 5.0 4.50-5.90
HGB 12.5 12.0-18.0

I used Mirth about 10 years ago and realize I have forgotten pretty much everything and a lot of my resources are no longer available. I am looking to iterate through OBR and OBX segments to pull the OBR 4.2, 7.1, 16.2 to be used as a section header and OBX 3.2, 5.1, 7.1 fields to show below on the report.

Basically take this:

MSH|^~\&|LAB|LIS||EMR|202107201651||ORU^R01|082017045701|P|2.3|| |NE|NE
PID|1||M1302^^^MR||TEST^PATIENT^T^^||19670101|M 123 8th street^apt.22b^long beach^CA^90802^||(714)555-1212|(714)222-5555|873lfif|4441113|
PV1|1|O|RGH^^^RGH^^^^|999999^TEST^TEST^^^^^L|288^ALBRIGHT^MD^^^^^L ||V4735|201008201648|
ORC|RE||15175288^ALBRIGHT^MD^^^^^L|
OBR|1||15175|CBC^COMPLETE BLOOD COUNT^L|R|202107200800|202107200800BB^RGH^^^^^^ ^^^^^^RGH|201008201648|B|288^ALBRIGHT^MD^^^^^L| ||20100820170246F|^||100.0||G A
OBX|1|NM|WBC^WBC^L||4.0|10\S\3/MM\S\3|3.6-11.1|F202107200759|RGH|ADM
OBX|2|NM|RBC^RBC^L||5.0|10\S\6/MM\S\3|4.50-5.90|F202107200758|RGH|ADM
OBX|3|NM|HGB^HGB^L||12.5|g/dL|12.0-18.0|F202107200757|RGH|ADM
ORC|RE||15175288^ALBRIGHT^MD^^^^^L|
OBR|2||15175|ALC^ALCOHOL,ETHYL^L|R|202107201650|20 1008201648BB^RGH^^^^^^^^^^^^RGH|201008201648 |B|288^ALBRIGHT^MD^^^^^L20100820170246F|^ |GA
OBX|1|NM|ALC^ALCOHOL (ETHANOL)^L||36|mg/dL|0-32|HF201008201650|RGH|ADM

and make:

CBC 202107260800 ALBRIGHT
WBC 4.0 3.6-11.1
RBC 5.0 4.50-5.90
HGB 12.5 12.0-18.0
ALCOHOL, ETHYL 202107201650 ALBRIGHT
ALCOHOL (ETHANOL) 36 0-32

Any assistance is greatly appreciated.

Share Improve this question asked Jul 26, 2021 at 18:01 j creedonj creedon 331 silver badge5 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 9

You can play around with the html and css still, but here's how you can organize the data and loop over it in velocity. We start by looping over the OBR segments. Then we use the getSegmentsAfter function for getting the OBX segments associated with the current OBR segment. The function returns the results as an array of xml objects, which we then convert to plain js objects.

The code template for the getSegmentsAfter function can be found here https://github./nextgenhealthcare/connect-examples/tree/master/Code%20Templates/Get%20Segments%20After%20a%20Particular%20Segment

This works because javascript arrays implement the java.util.Collection interface, and javascript objects implement the java.util.Map interface, both of which velocity knows how to access.

Transformer

var reportData = [];
for each (var obr in msg.OBR) {
    var  sectionHeader = {
        panelName: obr['OBR.4']['OBR.4.2'].toString().trim(),
        dateTime: obr['OBR.7']['OBR.7.1'].toString().trim(),
        providerName: obr['OBR.16']['OBR.16.3'].toString().trim() + ' ' + obr['OBR.16']['OBR.16.2'].toString().trim()
    };
    var sectionData = getSegmentsAfter(msg, obr, 'OBX')
        .map(function(obx) {
            return {
                testName: obx['OBX.3']['OBX.3.2'].toString().trim(),
                result: obx['OBX.5']['OBX.5.1'].toString().trim(),
                unitOfMeasure: obx['OBX.6']['OBX.6.1'].toString().trim(),
                referenceRange: obx['OBX.7']['OBX.7.1'].toString().trim(),
                abnormalFlag: obx['OBX.8']['OBX.8.1'].toString().trim()
            }});
    reportData.push({
        header: sectionHeader,
        data: sectionData
    });
}
$co('reportData', reportData);

Document Writer template

<html>
<head>
  <style type="text/css">
  div table {
    width: 100%;
    margin-bottom: 5px;
  }
  div table th, td {
    word-wrap: break-word;
    border: 1px solid lightgrey;
    text-align: left;
  }
  div {
    border: 1px solid grey;
    margin: 5px;
  }
  </style>
</head>
<body>
  <h1>Laboratory Results</h1>

  #foreach ($section in $reportData)
  <div>
  <table>
  <tr>
    <th>Panel Name</th><th>DateTime</th><th>Provider</th>
  </tr>
  <tr>
    <td>$section.header.panelName</td>
    <td>$section.header.dateTime</td>
    <td>$section.header.providerName</td>
  </tr>
  </table>

  <table>
  <tr>
    <th>Test</th><th>Result</th><th>Unit of Measure</th><th>Range</th><th>Flag</th>
  </tr>
    #foreach ($row in $section.data)
    <tr>
      <td>$row.testName</td>
      <td>$row.result</td>
      <td>$row.unitOfMeasure</td>
      <td>$row.referenceRange</td>
      <td>$row.abnormalFlag</td>
    </tr>
    #end
  </table>
  </div>
  #end
</body>
</html>

Results

Mirth User Guide provides some interesting documentation about what you are trying to achieve. There is a section named Iterating Over Message Segments which explains it and gives some examples.

But the idea is quite similar the following

//To iterate over all segments, follow this example:
for each (var segment in msg.children()) {
  if (segment.name().toString() == "ORC") {
    // Do something...
  }
} 

//To iterate through specifically named segments, use this formula:

for each (var segment in msg.OBX) {
  // Do something...
}

The plex part will be how to associate each OBX with its corresponding OBR and OCR. I dit not find a clean way to achieve this. I used Lists and Maps and process all segments sequentially, adding the relevant fields to some data structures which help me to get my final result. That table in your case.

Here is what I've done, it is super ugly and doesn't quite meet my expectations (yet) so please feel free to help me improve. I could not seem to get a nested foreach in the report writer's html to process through a 2nd OBR, so lets just hope I don't get one until I figure it out.

Source Transformer: I mapped the Patients info using the Mapper

Destination Transformer:

var _OBR45PanelName = Lists.list();
var _OBR71DateTime = Lists.list();
var _OBR163ProviderFirstName = Lists.list();
var _OBR162ProviderLastName = Lists.list();
var _OBX32TestName = Lists.list();
var _OBX51Result = Lists.list();
var _OBX61UnitofMeasure = Lists.list();
var _OBX71ReferenceRange = Lists.list();
var _OBX81AbnormalFlag = Lists.list();
for (var i = 0; i < getArrayOrXmlLength(msg['OBR']); i++) {
    var mapping;
    try {
        mapping = msg['OBR'][i]['OBR.4']['OBR.4.5'].toString().trim();
    } catch (e) {
        mapping = '';
    }
    _OBR45PanelName.add(validate(mapping, '', new Array()));
    var mapping;
    try {
        mapping = msg['OBR'][i]['OBR.7']['OBR.7.1'].toString().trim();
    } catch (e) {
        mapping = '';
    }
    _OBR71DateTime.add(validate(mapping, '', new Array()));
    var mapping;
    try {
        mapping = msg['OBR'][i]['OBR.16']['OBR.16.3'].toString().trim();
    } catch (e) {
        mapping = '';
    }
    _OBR163ProviderFirstName.add(validate(mapping, '', new Array()));
    var mapping;
    try {
        mapping = msg['OBR'][i]['OBR.16']['OBR.16.2'].toString().trim();
    } catch (e) {
        mapping = '';
    }
    _OBR162ProviderLastName.add(validate(mapping, '', new Array()));
    for (var J = 0; J < getArrayOrXmlLength(msg['OBX']); J++) {
        var mapping;
        try {
            mapping = msg['OBX'][J]['OBX.3']['OBX.3.2'].toString().trim();
        } catch (e) {
            mapping = '';
        }
        _OBX32TestName.add(validate(mapping, '', new Array()));
        var mapping;
        try {
            mapping = msg['OBX'][J]['OBX.5']['OBX.5.1'].toString().trim();
        } catch (e) {
            mapping = '';
        }
        _OBX51Result.add(validate(mapping, '', new Array()));
        var mapping;
        try {
            mapping = msg['OBX'][J]['OBX.6']['OBX.6.1'].toString().trim();
        } catch (e) {
            mapping = '';
        }
        _OBX61UnitofMeasure.add(validate(mapping, '', new Array()));
        var mapping;
        try {
            mapping = msg['OBX'][J]['OBX.7']['OBX.7.1'].toString().trim();
        } catch (e) {
            mapping = '';
        }
        _OBX71ReferenceRange.add(validate(mapping, '', new Array()));
        var mapping;
        try {
            mapping = msg['OBX'][J]['OBX.8']['OBX.8.1'].toString().trim();
        } catch (e) {
            mapping = '';
        }
        _OBX81AbnormalFlag.add(validate(mapping, '', new Array()));
    }
}
channelMap.put('OBR4.5 Panel Name', _OBR45PanelName.toArray());
channelMap.put('OBR7.1 DateTime', _OBR71DateTime.toArray());
channelMap.put('OBR16.3 Provider FirstName', _OBR163ProviderFirstName.toArray());
channelMap.put('OBR16.2 Provider LastName', _OBR162ProviderLastName.toArray());
channelMap.put('OBX3.2 Test Name', _OBX32TestName.toArray());
channelMap.put('OBX5.1 Result', _OBX51Result.toArray());
channelMap.put('OBX6.1 Unit of Measure', _OBX61UnitofMeasure.toArray());
channelMap.put('OBX7.1 Reference Range', _OBX71ReferenceRange.toArray());
channelMap.put('OBX8.1 Abnormal Flag', _OBX81AbnormalFlag.toArray());

For the report writer I have:

<html>
<head>
<style type="text/css">
div table {
    float: left;
}
div table th, td {
    word-wrap: break-word;
    border: 1px solid lightgrey;
    padding-right: 5px;
    height: 25px;
    text-align: left;
}
</style>
</head>
<body>
<h1>Laboratory Results</h1>
<table>
<tr><th>Name:</th><th>DOB:</th></tr>
<tr><td>${maps.get('PID5.2 Patient FirstName')} ${maps.get('PID5.3 Patient MiddleName')} ${maps.get('PID5.1 Patient LastName')}</td><td>${maps.get('PID7.1 Patient DoB')}</td></tr>
<tr><th>Ordering Provider:</th><td>${maps.get('OBR16.3 Provider FirstName')} ${maps.get('OBR16.2 Provider LastName')}</td></tr>
</table>

<table>
#foreach ($item in ${maps.get('OBR4.5 Panel Name')})
<tr><th>${maps.get('OBR4.5 Panel Name')}</th></tr>
<div>
<table>
<tr><th>Test</th></tr>
#foreach ($item in ${maps.get('OBX3.2 Test Name')})
<tr><td>$item</td></tr>
#end
</table>
<table>
<tr><th>Result</th></tr>
#foreach ($item in ${maps.get('OBX5.1 Result')})
<tr><td>$item</td></tr>
#end
</table>
<table>
<tr><th>Unit of Measure</th></tr>
#foreach ($item in ${maps.get('OBX6.1 Unit of Measure')})
<tr><td>$item</td></tr>
#end
</table>
<table>
<tr><th>Range</th></tr>
#foreach ($item in ${maps.get('OBX7.1 Reference Range')})
<tr><td>$item</td></tr>
#end
</table>
<table>
<tr><th>Flag</th></tr>
#foreach ($item in ${maps.get('OBX8.1 Abnormal Flag')})
<tr><td>$item</td></tr>
#end
</table>
</div>
#end
</table>
</body>
</html>

and it turns out (again ugly) like this

本文标签: javascriptNextGen Mirth Loop through all OBROBX segments for output to Document WriterStack Overflow