Skip to content

Composing a new HL7 message

Jaime Olivares edited this page Oct 18, 2024 · 3 revisions

Object construction

Create an empty Message object

Message message = new Message();

Adding a message header

For adding a header segment to a new message object, use the AddSegmentMSH() method, after constructing an empty message:

message.AddSegmentMSH(sendingApplication, sendingFacility, 
    receivingApplication, receivingFacility,
    security, messageType, 
    messageControlId, processingId, version);

⚠️ Notice that every HL7 message needs a header segment to be considered valid

Serialization

A message can be serialized as a string by using the Message.SerializeMessage() method. The method accepts an optional boolean argument for enabling validation before serializing.

This flag is useful for some scenarios where it is needed to validate a message against its original value.

Creating fields

Adding repeating field

var enc = new HL7Encoding();
Segment PID = new Segment("PID", enc);
Field f = new Field(enc);
f.HasRepetitions = true;

// Adding field f1 to f
Field f1 = new Field("A", enc);
f.AddRepeatingField(f1);

// Adding field f2 to f
Field f2 = new Field("B", enc);
f.AddRepeatingField(f2);

Update the value of any field i.e. to update PV1.2 – patient class

message.SetValue("PV1.2", "I");

// OR

message.Segments("PV1")[0].Fields(2).Value = "I";

Generate ACKs

To generate an ACK message

Message ack = message.GetACK();

To generate negative ACK (NACK) message with error message

Message nack = message.GetNACK("AR", "Invalid Processing ID");

It may be required to change the application and facility fields

Message ack = message.GetACK();
ack.SetValue("MSH.3", appName);
ack.SetValue("MSH.4", facility);

⚠️ Take into account that a message shall be previously parsed before attempting to generate an ACK or NACK message.

Creating Components

Update the value of any component

message.Segments("PID")[0].Fields(5).Components(1).Value = "Jayant";

// OR

message.SetValue("PID.5.1", "Jayant");

Adding new Segment

// Create a Segment with name ZIB
Segment newSeg = new Segment("ZIB");
 
// Create Field ZIB_1
Field ZIB_1 = new Field("ZIB1");
// Create Field ZIB_5
Field ZIB_5 = new Field("ZIB5");
 
// Create Component ZIB.5.2
Component com1 = new Component("ZIB.5.2");
 
// Add Component ZIB.5.2 to Field ZIB_5
// 2nd parameter here specifies the component position, for inserting segment on particular position
// If we don’t provide 2nd parameter, component will be inserted to next position (if field has 2 components this will be 3rd, 
// If field is empty this will be 1st component
ZIB_5.AddNewComponent(com1, 2);
 
// Add Field ZIB_1 to segment ZIB, this will add a new filed to next field location, in this case first field
newSeg.AddNewField(ZIB_1);
 
// Add Field ZIB_5 to segment ZIB, this will add a new filed as 5th field of segment
newSeg.AddNewField(ZIB_5, 5);
 
// Add segment ZIB to message
bool success = message.AddNewSegment(newSeg);

New Segment would look like this:

ZIB|ZIB1||||ZIB5^ZIB.5.2

After evaluated and modified required values, the message can be obtained again in text format

string strUpdatedMsg = message.SerializeMessage();

Remove Trailing Components

var message = new Message();

// create ORC segment
var orcSegment = new Segment("ORC", message.Encoding);

// add fields
for (int eachField = 1; eachField <= 12; eachField++)
{
    orcSegment.AddEmptyField();
}

// add components to field 12
for (int eachField = 1; eachField < 8; eachField++)
{
    orcSegment.Fields(12).AddNewComponent(new Component(message.Encoding));
}

// add values to components
orcSegment.Fields(12).Components(1).Value = "should not be removed";
orcSegment.Fields(12).Components(2).Value = "should not be removed";
orcSegment.Fields(12).Components(3).Value = "should not be removed";
orcSegment.Fields(12).Components(4).Value = ""; // should not be removed because in between valid values
orcSegment.Fields(12).Components(5).Value = "should not be removed";
orcSegment.Fields(12).Components(6).Value = ""; // should be removed because trailing
orcSegment.Fields(12).Components(7).Value = ""; // should be removed because trailing
orcSegment.Fields(12).Components(8).Value = ""; // should be removed because trailing

orcSegment.Fields(12).RemoveEmptyTrailingComponents();
message.AddNewSegment(orcSegment);

string serializedMessage = message.SerializeMessage();

Remove a Segment

Segments are removed individually, including the case where there are repeated segments with the same name

    // Remove the first segment with name NK1
    bool success = message.RemoveSegment("NK1") 

    // Remove the second segment with name NK1
    bool success = message.RemoveSegment("NK1", 1) 

Encoded segments

Some contents may contain forbidden characters like pipes and ampersands. Whenever there is a possibility of having those characters, the content shall be encoded before calling the 'AddNew' methods, like in the following code:

var obx = new Segment("OBX", new HL7Encoding());
// OR
var obx = new Segment("OBX", message.Encoding);

// Not encoded. Will be split into parts.
obx.AddNewField("70030^Radiologic Exam, Eye, Detection, FB^CDIRadCodes");  

// Encoded. Won't be parsed nor split.
obx.AddNewField(obx.Encoding.Encode("domain.com/resource.html?Action=1&ID=2"));  

⚠️ Segments must have the same encoding as the message. Otherwise, it will fail to serialize a valid message.

Copying a segment

The DeepCopy method allows to perform a clone of a segment when building new messages. Countersense, if a segment is referenced directly when adding segments to a message, a change in the segment will affect both the origin and new messages.

Segment pid = ormMessage.DefaultSegment("PID").DeepCopy();
oru.AddNewSegment(pid);