· Oct 21, 2016 3m read

Ensemble: How to embed a PDF file into an HL7 message

This article will describe and include an example of how to embed an external PDF file into an HL7 segment, specifically ADT_A01:2.3.1 OBX().  This can be useful when attempting to insert pictures or other external data into an HL7 message.  In this example, the name of the PDF file to be embedded is provided in the incoming HL7 message in OBX(1):ObservationValue field.

The basic stipulations for this example are as follows:

  1. Accept a PDF file
  2. Accept an HL7 message
  3. Using the name of the PDF file, embed the PDF data into the HL7 message
  4. Output the message to file









Using EnsLib.File.InboundAdapter, the example has two Business Services configured.  One to pull in PDF files using the built in EnsLib.File.PassthroughService.  The other to accept HL7 messages using the built in EnsLib.HL7.Service.FileService.

PDF Processing

The order of these components is key as the PDF file needs to be pulled in first.  It is also important that the PDF Business Service has an Archive Path and Work Path set to the same directory path.  This saves a copy of the PDF locally which is then used later to embed the data into the HL7 message. 

In order for the Business Service to save the PDF file into this Archive/Work Path directory, SendRequestAsyn() needs to be called.  This method is called by default when sending between Ensemble/HealthShare components.

To accomplish this, the PDF Business Service is configured to send the PDF message to a custom Business Operation that accepts the message without performing any additional actions.

Note: The target component of the PDF Business Service is irrelevant for this example but it could be built to perform any additional actions with the PDF message.

HL7 Processing

The HL7 message from the Business Service is sent to a custom Business Process.  The Business Process calls a BPL that identifies and opens the correct PDF file and then calls a DTL to do the actual embedding of data into the HL7 message. 


=== BPL ===

The BPL performs the following tasks:

  1. Extract the PDF filename from the HL7 message
  2. Query the Ens.StreamContainer table, looking for entries that match the extracted filename
  3. Call a DTL to do the embedding
    1. See “DTL” section of article
  4. The BPL then sends the message downstream to a built in EnsLib.HL7.Operaiton.FileOperation Business Operation


=== DTL ===

  1. Uses target.{OBX(*)} to count the number of OBX segments
  2. Increment the OBX count by one
  3. Adds the PDF data using StoreFieldStreamBase64() into a new OBX() segment
    1. See “DTL Code Action” for this code




=== DTL Code Action ===

//Get PDF stream object previously saved

   Set pdfStreamContainer = ##Class(Ens.StreamContainer).%OpenId(context.StreamContainerID)

   Try {

     Set pdfStreamObj = pdfStreamContainer.StreamGet()


   Catch {

      $$$TRACE("Error opening stream object ID = "_context.StreamContainerID)



 //Set PDF stream object into new OBX:5 segment

   Set status = target.StoreFieldStreamBase64(pdfStreamObj,"OBX("_count_"):ObservationValue(1)")

   Set ^testglobal("status",$H) = status

Sample Production

The following is a list of the files included in the attached sample.

  1. The initial HL7 message with only the PDF filename embedded into OBX(1)
  2. The sample PDF file
  3. A class export that includes the following:
    1. Production class
    2. Custom PDF Business Operation
    3. Routing Rule
    4. BPL
    5. DTL


This example was built on Ensemble 2016.2.0 but has been tested on Ensemble 2015.1.2 with no compatibility issues.  The .zip file can be found here:

Discussion (4)2
Log in or sign up to continue

I've just tried something very similar but the pdf files are transferred in via ftp (set to binary) and out by ftp.

I seem to have the base64 output in the OBX segment with \X0D\\X0A\ within it.  If I decode the base64 and copy into a pdf file I get a corrupt message but if I strip out the \X0D\\X0A\ manually and then decode and create a pdf file then it seems fine.

I have added a ..ReplaceStr(target.{OBX(1):5(1).3},"\X0D\\X0A\") for the moment.

Any ideas?  I am using the Ens.StreamContaininer to get the Stream Container ID and then using the code within the DTL to populate my OBX segment.