Thursday, 8 November 2018

Writing Base64 encoded HL7 data to a Binary file

It is common to have Base64 encode data in an OBX-5 field. The most common I've come across are PDF documents, but also .Doc, Docx and other Document formats are common, as are the many image formats - TIFF, PNG, JPG, and BMP.

HL7 Soup is now my go-to HL7 integration engine for binary formats as it's just so simple, while at the same time it's totally flexible.  Let me show you. 

Create a receiver workflow that receives an HL7 message and then writes it out to a file.

In the transformers of the “File Writer” activity, drag the OBX-5 into the transformers list to create a new variable.


Then back in the “File Writer” change the message template to write out the variable (delete the default message template, the right click in message template and insert variable).


Now Just change the message type of the file you want to write to binary and you’ll have a binary file.


And that is it done.  Writing out a binary file automatically decodes the value from base64.  No mucking about with code or anything fiddly like that.  

OK, but what if it wasn’t actually binary data, you just had base64 encoded text for instance?  Well, you also have the option to right click on the variable and tell it to base64 decode the value like so. 




There are lots of different types of encoding available too.  Depending on the Message Type you select, you get different options.  E.g. if I had written out an XML document then right-clicking on the variable would allow me to "XML Encode" the data which replaces the &'s & etc.

Sunday, 12 August 2018

Get Patient Email Address from HL7 repeat Fields

The HL7 inbound messages I was receiving were a bit inconsistent on where to find the patient emails.  Basically, I need to look at the PID-14 and all repeating instances of this, one at a time until I find an email address.
It sounded to me like a good opportunity to try out HL7 Soups custom parameters, where I can code up my logic in c#.

Firstly I went through there introduction video on custom transformers, and then grabbed the sample code to base mine transformer on. 

I must say that I love the API, it makes coding with HL7 super easy.  The trick I found is to make sure you typecast the messages to IHL7Message right at the beginning.  It gives you heaps more methods and properties than the basic IMessage type (which is generic because it also works with JSON, CSV, etc).

The only thing I tripped up on was finding the repeat fields themselves.  I thought they may have been accessible on the GetFields() method, so I mucked around there for a bit.  But actually, they are a property of IField.  I just needed to call GetRelatedRepeatFields(), and it gave me an iterator that included the original field and its siblings.

The deployment was easy, and I loved the debugging right in Visual Studio.  So much easier than having to log out each line like in Mirth.

Anyway, here is the code I created, hope it helps.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HL7Soup.Integrations;

namespace CustomTransformersSample
{
    [Variable("Patient Email", "sample@sample.com")]
    [DisplayName("Find Patient Email")]
    public class FindPatientEmail : CustomTransformer
    {
        public override void Transform(IWorkflowInstance workflowInstance, IMessage message, Dictionary<string, string> parameters)
        {
            string email = "";
            //Get the incoming message
            IHL7Message hl7 = workflowInstance.Activities[0].Message as IHL7Message;

            //Find the PID-14
            IHL7Field pid14 = (IHL7Field)hl7.GetPart("PID-14");
            if (pid14 != null)
            {
                //Look at all the PID 14s
                foreach (var repeatField in pid14.GetRelatedRepeatFields())
                {
                    //Get the 4th component (which is email)
                    IHL7Component component = repeatField.GetComponent("4");
                    if (component != null && component.Text != "")
                    {
                        //Found the email.  Return it.
                        email = component.Text;
                        break;
                    }
                }
            }

            workflowInstance.SetVariable("Patient Email", email);
        }
    }

}