• Inner Harbour Software

    Inner Harbour Software consists of a dedicated team of .Net programmers whose mission is to create exceptional and affordable HL7 products. Please email us at support@HL7Spy.com to contact us with questions regarding our products or services.
  • Home
  • /Posts Tagged 'custom'

Posts Tagged ‘custom’

How to handle Z-Segments in Custom Code

Question:
How can we handle Z-Segments in HL7Spy’s Custom Code Tool?

Answer:
The following code demonstrates how use Z-Segments. We start by adding a couple of ZF1 segments (1), then we set a few fields (2), and finally print the fields out using the Log function.

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  // (1) Append a couple of ZF1 segments
  message.Append(new Segment("ZF1")); // Append ZF1
  message.Append(new Segment("ZF1")); // Append a second ZF1
  string today=DateTime.Today.ToString("yyyyMMdd");
  int count=0;
  foreach(Segment zf1 in message.GetSegments("ZF1"))
  {
    ++count;
    //(2) set ZF1-3.1, and ZF1-3.2 with information from the MSH 
    zf1[3,1,1] = message.MSH[3,1,1] + "-V" + today;
    zf1[3,1,2] = message.MSH[9,1,2] + "-TEST";
    zf1[6] = count.ToString();
  }
  
  // (3) Log the information out using the Hl7Message class
  string firstZF1_6 = message["ZF1-6"];
  string secondZF1_6 = message["ZF1[2]-6"];
  Log(Severity.Informational,string.Format("ZF1-6={0}", firstZF1_6));
  Log(Severity.Informational,string.Format("ZF1[2]-6={0}",secondZF1_6));
  
  // save the message out to a new tab
  SaveMessage(message, "Modified Messages");  
}

Find last known allergies for each patient

Question:
How can we use HL7Spy to find the last set of known allergies for each patient in a set of messages?

Answer:
The best way is to write a custom function that remembers the last set of allergies for each patient. Then in the OnFinished function we print out all patients with their last set of known allergies.

string _fileName = @"c:\temp\_test.txt";
Dictionary<string,Patient> _data = new Dictionary<string,Patient>(10000);

public class Patient
{
   public Patient(string patientId) 
   { 
    Allergies = new HashSet<string>();
    PatientId = patientId;
   }
   public HashSet<string> Allergies;
   public string PatientId;
}

public override void Run() { 
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  MSH msh = message.Segments.First<MSH>();
  if(msh==null || msh.MessageType_09.TriggerEvent_02.Value!="A08")
    return; // not an ADT^A08 message
  
  PID pid = message.Segments.First<PID>();
  if(pid==null)
    return; // no pid segment
  
  List<AL1> patientAllergies = message.Segments.OfType<AL1>();
  if(patientAllergies.Count==0)
    return; // no allergies
  
  string patientId = pid.PatientIdentifierList_03.First.ToString();  
  
  Patient pat;
  if(!_data.TryGetValue(patientId,out pat))
  {
     pat = new Patient(patientId); 
     _data.Add(patientId,pat);
  }
  
  pat.Allergies.Clear();
  
  // loop through all AL1 segments
  foreach(AL1 al1 in patientAllergies)
  {
     pat.Allergies.Add(al1.AllergenTypeCode_02.ToString());
   }
}
// Called once after the last message has been processed.
// It is a good place to perform cleanup and to report information.
// Always called from the UI thread.
public override void OnFinish() 
{
  // to figure out the distribution of all allergies
  Dictionary<string, int> allergies = new Dictionary<string,int>(1000);
  
  // write the data out to a file
  using(System.IO.StreamWriter wr = new System.IO.StreamWriter(_fileName))
  {   
    wr.WriteLine("Patient ID vs Allergy for {0} patient samples",_data.Count);
    wr.WriteLine();
   
    foreach(Patient p in _data.Values.OrderByDescending(p=>p.Allergies.Count))
    {
        wr.Write(p.PatientId);
        wr.Write(',');
        wr.Write(p.Allergies.Count); 
        foreach(string s in p.Allergies)
        {
           wr.Write(',');
           wr.Write(s);         
           // calculate the total number of allergy types for the given set of patients
           int frequency=0;
           if(!allergies.TryGetValue(s,out frequency))
           {
              allergies.Add(s,1);
           } else {
              allergies[s]=++frequency;
           }
        }
        wr.WriteLine();
    }
    
    wr.WriteLine();
    wr.WriteLine();
    wr.WriteLine("Allergy distribution for {0} patient samples.",_data.Count);
    wr.WriteLine("Number of distinct allergies is {0}.",allergies.Count);    
    wr.WriteLine();
    
    foreach(KeyValuePair<string,int> d in allergies)
    {
      wr.Write(d.Key);
      wr.Write(',');
      wr.Write(d.Value);
      wr.WriteLine();
    }       
  }
// launch notepad to display the file.
System.Diagnostics.Process.Start("Notepad",_fileName);
 }

Segments where OBX-15 differ from each other

Question:
Dear HL7Spy,
A user has a request – am not able to find function within HL7 to execute.

Find all the segments(i.e. OBX 15:1) within a message where content is different from each other. For example: If first OBX 15:1 is ABC, then find all other OBX within same message with content other than ABC.

Not sure if HL7Spy has that capability but thought I’d check.

Answer:
Sure, no problem, you can write a custom function to display all messages where this is true in a few lines of code.

To add this code, go to the Custom Code tool, select the “+” to add a new custom function, and cut and paste this code over-top of the default code that is displayed.

To run the code, load up a set of messages into a tab and click “Run”. What you should see is a new tab created that will contain any messages where the OBX-15 value differs between segments.

 public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  string obx15 = null;
  foreach(OBX obx in message.Segments.OfType<OBX>())
  {
    if(obx15==null)
    {
      obx15 = obx.ProducerSID_15.Value;
    }
    else if(obx15 != obx.ProducerSID_15.Value)
    {
      SaveMessage(message,"Different OBX-15");
      break;  
    }
  } 
} 

Find the last ADT^A08 message for each patient in the message collection?

Question:
How can I find the last ADT^A08 message for every patient in a collection of messages?

Answer:
The best way to do this is to create a dictionary based on the patient Medical Record Number (PID-3). For each message receive. Look up the patient in the dictionary, if there is no entry, add one. Otherwise, replace the existing entry’s message with the new version. See the code below.

string _fileName = @"c:\_test.txt";
Dictionary<string,Patient> _data = new Dictionary<string,Patient>(10000);

public class Patient
{
   public Patient(string patientId)
   {
    PatientId = patientId;
   }

   public IMessageData Message;
   public string PatientId;
}

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  MSH msh = message.GetFirstSegment<MSH>();
  if(msh==null || msh.MessageType_09.TriggerEvent_02.Value!="A08")
    return; // not an ADT^A08 message

  PID pid = message.GetFirstSegment<PID>();
  if(pid==null)
    return; // no pid segment

  string patientId = pid.PatientIdentifierList_03.First.Value; 
  Patient pat;
  if(!_data.TryGetValue(patientId,out pat))
  {
     pat = new Patient(patientId);
     _data.Add(patientId,pat);
  }

  pat.Message = Message;
}

// Called once after the last message has been processed.
// It is a good place to perform cleanup and to report information.
// Always called from the UI thread.
public override void OnFinish()
{
   SaveMessage(_data.Values.Select(p=>p.Message),"Last A08");
}

Capture EVN-1, PID-3, PV1-2, FT1-2 to file

Question:
How can I capture a list of the following fields: EVN-1, PID-3, PV1-2, FT1-2 in a comma delimited list?
Answer:
Custom code is the best approach if you are expecting repeated FT1 segments. The following code will create a file in the c:\temp directory containing the specified list, and will display in Notepad upon completion.

string _fileName = @"c:\temp\_test.txt";
StreamWriter _file;

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  // Get the first FT1 segment
  EVN evn = message.Segments.OfType<EVN>().FirstOrDefault();
  PID pid = message.Segments.OfType<PID>().FirstOrDefault();
  PV1 pv1 = message.Segments.OfType<PV1>().FirstOrDefault();
  foreach(FT1 ft1 in message.Segments.OfType<FT1>())
  {
    _file.Write("{0},",evn != null ? evn.EventTypeCode_01.Value : null);
    _file.Write("{0},",pid != null ? pid.PatientIdentifierList_03.First.Value : null);
    _file.Write("{0},",pv1 != null ? pv1.PatientClass_02.Value : null);
    _file.Write("{0},",ft1 != null ? ft1.TransactionID_02.Value : null);
    _file.WriteLine();
  }
}

public override void OnStart()
{
  // create the file to be written out
  _file = new StreamWriter(_fileName,false);
  _file.WriteLine("EVN_EVENT_TYPE, PID_MRN, PV1_PATIENTCLAS", "FT1_TRANS_ID");
}

// Called once after the last message has been processed.
// It is a good place to perform cleanup and to report information.
// Always called from the UI thread.
public override void OnFinish() {
  // sort the data
  _file.Close();
  // launch notepad to display the file.
  System.Diagnostics.Process.Start("Notepad",_fileName);
}

Messages with duplicate OBR-3.1 to a new tab

Question:
I’m looking the way to get “DISTINCT” OBR-3.1 value messages. How can I do this in custom code. I want to show any messages that have duplicate OBR-3.1 values to a new tab. Please note we have multiple OBR segments per message.

Answer:
The following code should do the trick.

private class TrackedItem
{
   public List<IMessageData> Messages=new List<IMessageData>();
   public int Index {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);

public override void OnStart() {
  _knownValues.Clear();
}

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  OBR obr = message.Segments.First<OBR>();
  if(obr != null && !string.IsNullOrEmpty(obr.FillerOrderNumber_03.Value))
  {
    string obrIdentifier = obr.FillerOrderNumber_03.Value;
    TrackedItem item;
    if(!_knownValues.TryGetValue(obrIdentifier,out item))
    {
       item = new TrackedItem();
       _knownValues.Add(obrIdentifier,item);
    } else
    {
       Log(Severity.Informational,string.Format("duplicates found at index",MessageIndex));
       if(item.Index==0)
        item.Index = MessageIndex;
    }
    item.Messages.Add(Message);
  }
}

public override void OnFinish() {
  var list = _knownValues.Values.Where(i=>i.Messages.Count>1).ToList();
  Log(Severity.Informational,string.Format("{0} duplicates found",list.Count));
  foreach(TrackedItem item in list)
  {
    SaveMessage(item.Messages,"Duplicates");
  }
}

How do I create test data from a set of messages?

Question:
I would like to book some of you and or your teams time to develop or enhance HL7spy custom codes or product for my team. We would like the custom code to do the following:

  1. Take HL7 transactions (loaded in the Query Results tab)
  2. Append “-” + OBR-2.1 … to OBR-3.1 + “-” + some variable, ‘date yyyymmdd’
  3. Append “-” + some variable like “TEST” to OBR-3.2
  4. Delete the contents of OBR-2

Answer:
No need to hire us. This is pretty easy to do. There are two ways of accomplishing this: using type safe classes, and using field position specifications. Type safe classes provide the benefit of automatically documenting the code.

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  string today=DateTime.Today.ToString("yyyyMMdd");
  // loop through all the OBR segments in the message
  foreach(OBR obr in message.GetSegments<OBR>())
  {
    //(2) Append "-" + OBR-2.1 ... to OBR-3.1 + "-" + some variable, 'date yyyymmdd'
    obr.FillerOrderNumber_03.EntityIdentifier_01.Value = obr.PlacerOrderNumber_02.EntityIdentifier_01.Value + "-V" + today; 
    //(3) Append "-" + some variable like "TEST" to OBR-3.2
    obr.FillerOrderNumber_03.NamespaceID_02.Value = obr.FillerOrderNumber_03.NamespaceID_02.Value + "-TEST";
    //(4) Delete the contents of OBR-2
    obr.PlacerOrderNumber_02.Value = "";
    // save the message out to a new tab
    SaveMessage(message, "Modified Messages");
  }
}
public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  string today=DateTime.Today.ToString("yyyyMMdd");
  foreach(OBR obr in message.GetSegments<OBR>())
  {
    //(2) Append "-" + OBR-2.1 ... to OBR-3.1 + "-" + some variable, 'date yyyymmdd'
    obr[3,1,1] = obr[2,1,1] + "-V" + today;
    //(3) Append "-" + some variable like "TEST" to OBR-3.2
    obr[3,1,2] = obr[3,1,2] + "-TEST";
    //(4) Delete the contents of OBR-2
    obr[2] = "";
    // save the message out to a new tab
    SaveMessage(message, "Modified Messages");
  }
}

Find all unique OBX-3/OBR-3 values

Question:
Hi, I am using HL7Spy HL7 SQL for the first time and am trying to pull the values stored in obx-3.1.1 for repeating obx segments but it seems to be only pulling the first value. I thought that this query would accomplish what I needed but I do not believe it is.

SELECT OBx[*]-3.1.1,OBx[*]-3.2.1 WHERE OBx[*]-3.1.1 IS NOT NULL

I would also like to find all unique OBR-4 values too.

Answer:

The HL7 SQL function will only return one result per message, so it probably not what you are looking for.

It would be quite easy to write a Custom Function to do what you are looking for. Is your goal to get a list of OBX-3.1, OBX-3.2 pairs with perhaps a count of how many times each pair occurred? If so, here is some code that will do just that.

private class TrackedItem
{
   public string Key {get; set;}
   public string Value {get;set;}
   public int Counter {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);


public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  foreach(OBX obx in message.Segments.OfType<OBX>())
  {  
    string key = obx.ObservationIdentifier_03.Identifier_01.Value;   
    TrackedItem item;
    if(!_knownValues.TryGetValue(key,out item))
    {
       item = new TrackedItem {Key=key, Value=obx.ObservationIdentifier_03.Text_02.Value};
       _knownValues.Add(key,item);
    }
    item.Counter = item.Counter + 1;
  }
}

private string _fileName = @"C:\temp\_test.txt";
public override void OnFinish() {
  using(var stream = new System.IO.StreamWriter(_fileName))
  {
    stream.WriteLine("OBX-3.1, OBX-3.2, Count");
    foreach(TrackedItem item in _knownValues.Values.OrderByDescending(i=>i.Counter))
    {
      stream.Write(item.Key);    
      stream.Write("\t");
      stream.Write(item.Value);
      stream.Write("\t");
      stream.WriteLine(item.Counter.ToString());
    }
  }
 
  try{
    System.Diagnostics.Process.Start("Notepad",_fileName);
  } catch{}
}

And, a variation on the same theme for OBR-4

private class TrackedItem
{
   public string Key {get; set;}
   public string Value {get;set;}
   public int Counter {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  foreach(OBR obr in message.Segments.OfType<OBR>())
  {  
    string key = obr.universalServiceIdentifier_04.Identifier_01.Value;   
    TrackedItem item;
    if(!_knownValues.TryGetValue(key,out item))
    {
       item = new TrackedItem {Key=key, Value=obr.UniversalServiceIdentifier_04.Text_02.Value};
       _knownValues.Add(key,item);
    }
    item.Counter = item.Counter + 1;
  }
}

private string _fileName = @"C:\temp\_test.txt";
public override void OnFinish() {
  using(var stream = new System.IO.StreamWriter(_fileName))
  {
    stream.WriteLine("OBR-4.1, OBR-4.2, Count");
    foreach(TrackedItem item in _knownValues.Values.OrderByDescending(i=>i.Counter))
    {
      stream.Write(item.Key);    
      stream.Write("\t");
      stream.Write(item.Value);
      stream.Write("\t");
      stream.WriteLine(item.Counter.ToString());
    }
  }

  try{
    System.Diagnostics.Process.Start("Notepad",_fileName);
  } catch{}
}

Find all Unique OBR-4 – OBX-3 pairs in a message stream

Question:
Here is some custom code that you wrote for as a while back. The code exports a row for every unique OBR 4 and OBX 3 pair, and a count of the occurrences. This report is used by our lab mappers during the mapping process for a new laboratory. The lab mappers are requesting that the report contain additional information. Below is what they are requesting, with the more important item on top:

Include a full message with each OBR 4 – OBX 3 pair. It could be the 1st message for this pair, the last message for this pair, or any other message for this pair. Which message isn’t as import as actually having a message that contains the OBR 4 – OBX 3 pair. They plan to visually review this message as they are doing the mapping to resolve any issues with method, units, reference range, etc.

Include a list of OBR 4 terms only without any OBX information. They plan to use this for mapping the OBR 4 term, which we do for radiology and text reports.

Answer:
The following code will create a

private class TrackedItem
{
   public string Value {get;set;}
   public int Counter {get;set;}
}

Dictionary<string,TrackedItem> _knownValues = new Dictionary<string,TrackedItem>(StringComparer.CurrentCultureIgnoreCase);
private string _fileName = @"C:\temp\data.hl7";

public override void Run() {
  // Get an HL7 Message in parsed format
  Hl7Message message = GetParsedMessage();
  foreach(OBX obx in message.GetSegments<OBX>())
  {
    string obrIdentifier = message["OBR-4.1.1"];
    string obxIdentifier = obx.ObservationIdentifier_03.Identifier_01.Value;
    string key = (obrIdentifier + "-" + obxIdentifier).Trim();
    TrackedItem item;
    if(key=="-")
      continue;
    
    if(!_knownValues.TryGetValue(key,out item))
    {
       item = new TrackedItem();
       item.Value = string.Format("{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}",message["OBR-4.1"],message["OBR-4.2"],message["OBR-4.3"],obx.ObservationIdentifier_03.Identifier_01, obx.ObservationIdentifier_03.Text_02, obx.ObservationIdentifier_03.NameOfCodingSystem_03,obx.Units_06,obx.ReferencesRange_07);
       _knownValues.Add(key,item);
    }
    item.Counter = item.Counter + 1;
  }
}

public override void OnFinish() {
  using(var stream = new System.IO.StreamWriter(_fileName))
  {
    foreach(TrackedItem item in _knownValues.Values.OrderByDescending(i=>i.Counter))
    {
      stream.Write(item.Counter.ToString());
      stream.Write("|");
      stream.WriteLine(item.Value);
    }
  }
  
  try{
   // System.Diagnostics.Process.Start("Notepad",_fileName);
  } catch{}
}
  • Page 1 of 2
  • 1
  • 2