![]() |
VOOZH | about |
Prefer to use the new package HL7-V2. Documentation: https://github.com/Efferent-Health/HL7-V2
dotnet add package HL7-dotnetcore --version 2.39.1
NuGet\Install-Package HL7-dotnetcore -Version 2.39.1
<PackageReference Include="HL7-dotnetcore" Version="2.39.1" />
<PackageVersion Include="HL7-dotnetcore" Version="2.39.1" />Directory.Packages.props
<PackageReference Include="HL7-dotnetcore" />Project file
paket add HL7-dotnetcore --version 2.39.1
#r "nuget: HL7-dotnetcore, 2.39.1"
#:package HL7-dotnetcore@2.39.1
#addin nuget:?package=HL7-dotnetcore&version=2.39.1Install as a Cake Addin
#tool nuget:?package=HL7-dotnetcore&version=2.39.1Install as a Cake Tool
๐ NuGet
๐ downloads
๐ github
๐ build
This is a lightweight library for building and parsing HL7 2.x messages, for .NET Standard, .NET Core, and .NET 5+. It is not tied to any particular version of HL7 nor validates against one.
This library is distributed via nuget and targets two framworks:
For using the classes and methods mentioned below, declare de following namespace:
using HL7.Dotnetcore;
Message message = new Message(strMsg);
// Parse this message
bool isParsed = false;
try
{
isParsed = message.ParseMessage();
}
catch(Exception ex)
{
// Handle the exception
}
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
If the HL7 message is coming from a MLLP connection (see the official documentation), the message needs to be cleared from the MLLP prefixes and suffixes. Also, consider there can be more than one message in a single MLLP frame.
For this purpose, there is an ExtractMessages() method, to be used as follows:
// extract the messages from a buffer containing a MLLP frame
var messages = MessageHelper.ExtractMessages(buffer);
// construct and process each message
foreach (var strMsg in messages)
{
Message message = new Message(strMsg);
message.ParseMessage(); // Required by most operations
// do something with the message object
}
Message message = new Message(strMsg)
message.ParseMessage(true);
List<Segment> segList = message.Segments();
For example if there are multiple IN1 segments
List<Segment> IN1List = message.Segments("IN1");
Note index 1 will return the 2nd element from list
Segment IN1_2 = message.Segments("IN1")[1];
int countIN1 = message.Segments("IN1").Count;
Segment IN1 = message.DefaultSegment("IN1");
// OR
Segment IN1 = message.Segments("IN1")[0];
string SendingFacility = message.GetValue("MSH.4");
// OR
string SendingFacility = message.DefaultSegment("MSH").Fields(4).Value;
// OR
string SendingFacility = message.Segments("MSH")[0].Fields(4).Value;
string ContactPhone = message.GetValue("NK1(2).5"); // Second occurrence of NK1
bool isComponentized = message.Segments("PID")[0].Fields(5).IsComponentized;
// OR
bool isComponentized = message.IsComponentized("PID.5");
bool isRepeated = message.Segments("PID")[0].Fields(3).HasRepetitions;
// OR
bool isRepeated = message.HasRepetitions("PID.3");
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);
List<Field> repList = message.Segments("PID")[0].Fields(3).Repetitions();
Field PID3_R2 = message.GetValue("PID.3[2]");
// OR
Field PID3_R2 = message.GetValue("PID.3(2)");
message.SetValue("PV1.2", "I");
// OR
message.Segments("PV1")[0].Fields(2).Value = "I";
string version = message.Version;
string msgControlID = message.MessageControlID;
string messageStructure = message.MessageStructure;
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.
string PatName1 = message.GetValue("PID.5.1");
// OR
string PatName1 = message.Segments("PID")[0].Fields(5).Components(1).Value;
bool isSubComponentized = message.Segments("PV1")[0].Fields(7).Components(1).IsSubComponentized;
// OR
bool isSubComponentized = message.IsSubComponentized("PV1.7.1");
message.Segments("PID")[0].Fields(5).Components(1).Value = "Jayant";
// OR
message.SetValue("PID.5.1", "Jayant");
// 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();
var message = new Message();
// create ORC segment
var orcSegment = new Segment("ORC", new HL7Encoding());
// 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(new HL7Encoding()));
}
// 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(false);
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)
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());
// 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"));
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);
Null elements (fields, components or subcomponents), also referred to as Present But Null, are expressed in HL7 messages as double quotes, like (see last field):
EVN|A04|20110613083617||""
Whenever requested individually, those elements are returned as null, rather than double quotes:
var expectEmpty = evn.Fields(3).Value; // Will return an empty string
var expectNull = evn.Fields(4).Value; // Will return null
If this behavior is not desirable, it can be disabled by setting Encoding.PresentButNull to null before parsing:
var message = new Message(msg);
message.Encoding.PresentButNull = null;
message.ParseMessage();
A couple of date handling methods have been added, for parsing elements containing valid date/times, including time zones, as described in the HL7 standard. Examples:
// With time zone
string value1 = "20151231234500.1234+2358";
TimeSpan offset;
DateTime? dt1 = MessageHelper.ParseDateTime(value1, out offset);
// Date/time only
string value2 = "20151231234500";
DateTime? dt2 = MessageHelper.ParseDateTime(value2);
ParseDateTime will catch exceptions by default and return null in case of invalid dates. For preventing this mechanism, add an extra argument as true, like:
try
{
var dt1 = MessageHelper.ParseDateTime(value1, out TimeSpan offse, true);
var dt2 = MessageHelper.ParseDateTime(value2, true);
}
catch
{
// do something here
}
This is a fork from Jayant Singh's HL7 parser (2013). Since then, it has been modified fundamentally, with respect to features, code quality, bugs and typos. For more information about the original implementation read:
The field encoding and decoding methods have been based on https://github.com/elomagic/hl7inspector
Since version 2.9, the MSH segment will have an extra field at the beginning of the segment list, containing the field separator. This is according to the HL7 standard, as mentioned in Issue #26. Every field index in that segment should be increased by one.
Since version 2.9, some previously deprecated methods starting with lowercase have been removed. The replacement methods starting with uppercase shall be used instead.
Since version 2.21, message.GetValue() will decode the returned content. In version 2.33, it was homologated with the Value property.
Since version 2.39, the nuget package targets .NET 8.0, along with the long-supported .NET Standard 2.0.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 1 NuGet packages that depend on HL7-dotnetcore:
| Package | Downloads |
|---|---|
|
KH.HL7
ๅ่ฎฎๅบ็กๅบ |
This package is not used by any popular GitHub repositories.