internal static void Encode(HL7Separators seps, System.Text.StringBuilder sb, Type type, object value) { if (value == null) { // Do nothing } else if (type.IsArray) { foreach (object element in value as Array) { Encode(seps, sb, type.GetElementType(), element); sb.Append(seps.FieldRepeatSeparator); } // Remove the last field repeat separator. sb.Remove(sb.Length - 1, 1); } else if (type.Equals(typeof(string))) { sb.Append(seps.Encode(value as string)); } else { foreach (FieldInfo component in type.GetFields()) { HL7Component.Encode(seps, sb, component.FieldType, component.GetValue(value)); sb.Append(seps.ComponentSeparator); } // Remove the last component separator. sb.Remove(sb.Length - 1, 1); } }
internal void Encode(HL7Separators seps, System.Text.StringBuilder sb) { FieldInfo[] fields = GetType().GetFields(); sb.Append(GetType().Name); sb.Append(seps.FieldSeparator); foreach (FieldInfo field in fields) { if (this is MSH && field.Name.Equals("FieldSeparator")) { // A field separator was already added after the segment HL7Name, don't add another. } else if (this is MSH && field.Name.Equals("EncodingCharacters")) { // We want the encoding characters raw, not escaped. sb.Append(field.GetValue(this)); sb.Append(seps.FieldSeparator); } else { HL7Field.Encode(seps, sb, field.FieldType, field.GetValue(this)); sb.Append(seps.FieldSeparator); } } }
/// <summary> /// Encode message according to HL7 encoding rules with specified separators. /// </summary> /// <param HL7Name="seps">Characters to separate segments, fields, field repeats, components and subcomponents</param> /// <returns>Bytes for HL7 message</returns> public string Encode(HL7Separators seps) { StringBuilder sb = new StringBuilder(); // Encode this full message as a segment group base.Encode(seps, sb); return(Cleanup(seps, sb.ToString())); }
/// <summary> /// Parses the received HL7 message. /// </summary> /// <param name="messageForm">The raw message encoded in HL7 'pipes and hats' format.</param> /// <returns>The parsed HL7 message object</returns> /// <exception cref="HL7ParseException">Thrown when parsing fails</exception> public static HL7Message Parse(string messageForm) { // Determine the HL7 separators dynamically from the incoming message (usually "|^~\&") HL7Separators sep = new HL7Separators(messageForm); // Change CRLF or LF into the standard CR separators if (messageForm.Contains("\r\n")) { messageForm = messageForm.Replace("\r\n", "\r"); } if (messageForm.Contains("\n")) { messageForm = messageForm.Replace("\n", "\r"); } // Remove consecutive segment separators while (messageForm.Contains("\r\r")) { messageForm = messageForm.Replace("\r\r", "\r"); } // Parse all the segments messageForm = messageForm.TrimEnd(new char[] { sep.SegmentSeparator }); string[] segmentForm = messageForm.Split(sep.SegmentSeparator); for (int count = 0; count < segmentForm.Count(); count++) { segmentForm[count] = segmentForm[count].Replace("\n", string.Empty); } HL7Segment[] segments = new HL7Segment[segmentForm.Length]; for (int i = 0; i < segmentForm.Length; i++) { segments[i] = HL7Segment.Parse(segmentForm[i], sep); } // Grab the MSH segment in order to determine which message structure to use MSH msh = segments[0] as MSH; if (msh == null) { throw new HL7ParseException(ConstantsResource.HL7NoMshSegment); } if (msh.MessageType == null) { throw new HL7ParseException(ConstantsResource.NoMessageType); } // Determine the structure for the indicated message identifier Type messageStructure = GetMessageStructure(msh.MessageType); // Create the message and populate all the matching segments into its structure int segmentIndex = 0; HL7Message message = BuildSegmentGroup(messageStructure, segments, ref segmentIndex) as HL7Message; return(message); }
/// <summary> /// Encode segment group according to HL7 encoding rules with specified separators. /// </summary> /// <param HL7Name="seps">Characters to separate segments, fields, field repeats, components and subcomponents</param> /// <param HL7Name="sb">String builder</param> public void Encode(HL7Separators seps, StringBuilder sb) { var segmentGroupFields = GetType().GetFields().OrderBy(f => f.MetadataToken); foreach (FieldInfo segmentGroupField in segmentGroupFields) { if (segmentGroupField.FieldType.IsArray) { Array array = segmentGroupField.GetValue(this) as Array; foreach (object segmentGroupObject in array) { // Each item in the array could be another group of segments or a single segment if (segmentGroupObject is HL7SegmentGroup) { HL7SegmentGroup segmentGroup = segmentGroupObject as HL7SegmentGroup; segmentGroup.Encode(seps, sb); } else { HL7Segment segment = segmentGroupObject as HL7Segment; segment.Encode(seps, sb); sb.Append(seps.SegmentSeparator); } } } else { // The non-repeating item could be a another group of segments, or a single segment, or null object segmentGroupObject = segmentGroupField.GetValue(this); if (segmentGroupObject is HL7SegmentGroup) { HL7SegmentGroup segmentGroup = segmentGroupObject as HL7SegmentGroup; segmentGroup.Encode(seps, sb); } else if (segmentGroupObject != null) { HL7Segment segment = segmentGroupObject as HL7Segment; segment.Encode(seps, sb); sb.Append(seps.SegmentSeparator); } } } }
public static object Parse(Type type, string componentForm, HL7Separators sep) { object component; // A component can either be a string, or it will consist of sub-components. if (type.Equals(typeof(string))) { component = sep.Decode(componentForm); } else { FieldInfo[] subcomponents = type.GetFields(); string[] subcomponentForm = componentForm.Split(sep.SubcomponentSeparator); int n = Math.Min(subcomponents.Length, subcomponentForm.Length); // Invoke the constructor that takes no parameters component = type.GetConstructor(System.Type.EmptyTypes).Invoke(null); for (int i = 0; i < n; i++) { // Each subcomponent must be a string if (subcomponents[i].FieldType.Equals(typeof(string))) { subcomponents[i].SetValue(component, sep.Decode(subcomponentForm[i])); } else if (subcomponents[i].FieldType.Equals(typeof(HL7.Common.DataStructure.HD))) // For OBR segment PrincipalResultsInterpreter field we have assigningAuthority that needs to be set { object objHD = new HL7.Common.DataStructure.HD(); FieldInfo[] subcomponentsHD = objHD.GetType().GetFields(); for (int j = 0; j < subcomponentsHD.Length; j++) { if (subcomponentsHD[j].Name == "universalID") // Set the UniversalID { subcomponentsHD[j].SetValue(objHD, sep.Decode(subcomponentForm[i])); // subcomponents[i].SetValue(component, objHD); } } } else { throw new HL7ParseException(string.Format(ConstantsResource.SubcomponentNotString, subcomponents[i].GetType())); } } } return(component); }
public static object Parse(Type type, string fieldForm, HL7Separators sep) { object field; // A field can be an array of repeats, or a string identifier, or a data structure with components if (type.IsArray) { Type elementType = type.GetElementType(); string[] elementForm; if (fieldForm.IndexOf(sep.FieldRepeatSeparator) == -1 && fieldForm.IndexOf(sep.ComponentSeparator) > -1 && elementType.Equals(typeof(string))) { elementForm = fieldForm.Split(sep.ComponentSeparator); } else { elementForm = fieldForm.Split(sep.FieldRepeatSeparator); } Array array = Array.CreateInstance(elementType, elementForm.Length); for (int i = 0; i < elementForm.Length; i++) { array.SetValue(HL7Field.Parse(elementType, elementForm[i], sep), i); } field = array; } else if (type.Equals(typeof(string))) { field = sep.Decode(fieldForm); } else { FieldInfo[] components = type.GetFields(); string[] componentForm = fieldForm.Split(sep.ComponentSeparator); int n = Math.Min(components.Length, componentForm.Length); // Invoke the constructor that takes no parameters field = type.GetConstructor(System.Type.EmptyTypes).Invoke(null); for (int i = 0; i < n; i++) { object value = HL7Component.Parse(components[i].FieldType, componentForm[i], sep); components[i].SetValue(field, value); } } return(field); }
public static HL7Segment Parse(string segmentForm, HL7Separators sep) { // Split the segment into fields and create the object for the indicated segment identifier string[] fieldForm = segmentForm.Split(sep.FieldSeparator); HL7Segment segment = CreateBlankSegment(fieldForm[0]); if (segment == null) { return(new UnknownSegment() { FieldForm = fieldForm }); } // Parse each of the fields according to its declared identifier in the segment structure. // Some fields will be repeating, some will be strings and some will have components. PopulateSegment(sep, fieldForm, segment); return(segment); }
/// <summary> /// Cleans up an HL7 message by removing redundant separators. /// </summary> /// <param name="seps">The defined separators for the message</param> /// <param name="messageForm">The message to be cleaned up</param> /// <returns>The cleaned message</returns> private static string Cleanup(HL7Separators seps, string messageForm) { // Save the first 8 characters which contain the HL7 encoding characters that should not be normalised. const int PREAMBLE_LENGTH = 8; string preamble = messageForm.Substring(0, PREAMBLE_LENGTH); messageForm = messageForm.Substring(PREAMBLE_LENGTH); // e.g. input: a&^&~&^&|&^&~&^&\r // step 1: a^&~^&|^&~^&\r (removed & before ^) // step 2: a^~^&|^~^&\r (removed & before ~) // step 3: a^~^|^~^&\r (removed & before |) // step 4: a^~^|^~^\r (removed & before \r) // step 5: a~^|~^\r (removed ^ before ~) // step 6: a~|~^\r (removed ^ before |) // step 7: a~|~\r (removed ^ before \r) // step 8: a|~\r (removed ~ before |) // step 9: a|\r (removed ~ before \r) // step 10: a\r (removed | before \r) RemoveRedundantSeparator(ref messageForm, seps.SubcomponentSeparator, seps.ComponentSeparator); RemoveRedundantSeparator(ref messageForm, seps.SubcomponentSeparator, seps.FieldRepeatSeparator); RemoveRedundantSeparator(ref messageForm, seps.SubcomponentSeparator, seps.FieldSeparator); RemoveRedundantSeparator(ref messageForm, seps.SubcomponentSeparator, seps.SegmentSeparator); RemoveRedundantSeparator(ref messageForm, seps.ComponentSeparator, seps.FieldRepeatSeparator); RemoveRedundantSeparator(ref messageForm, seps.ComponentSeparator, seps.FieldSeparator); RemoveRedundantSeparator(ref messageForm, seps.ComponentSeparator, seps.SegmentSeparator); RemoveRedundantSeparator(ref messageForm, seps.FieldRepeatSeparator, seps.FieldSeparator); RemoveRedundantSeparator(ref messageForm, seps.FieldRepeatSeparator, seps.SegmentSeparator); RemoveRedundantSeparator(ref messageForm, seps.FieldSeparator, seps.SegmentSeparator); return(preamble + messageForm); }
/// <summary> /// Parses each of the fields according to its declared identifier in the segment structure. /// Ignores any extra fields either in the received segment or in the structure. /// </summary> /// <param HL7Name="sep">Separators to use for repeating fields, components and subcomponents</param> /// <param HL7Name="fieldForm">Encoded segment split into fields, where fieldForm[0] is the segment name</param> /// <param HL7Name="segment">Empty object of desired segment structure</param> private static void PopulateSegment(HL7Separators sep, string[] fieldForm, HL7Segment segment) { FieldInfo[] fields = segment.GetType().GetFields(); // Subtract one from the number of fields in the received segment to avoid counting the segment name. int offset = 1; // Except when segment is MSH, then have no offset but the first field is the field separator. if (fieldForm[0].Equals("MSH")) { fields[0].SetValue(segment, "" + sep.FieldSeparator); offset = 0; } int n = Math.Min(fields.Length, fieldForm.Length - 1); for (int i = 1 - offset; i < n; i++) { object value = HL7Field.Parse(fields[i].FieldType, fieldForm[i + offset], sep); fields[i].SetValue(segment, value); } }
/// <summary> /// Creates a negative HL7 acknowledgement for an unparseable message. /// </summary> /// <param HL7Name="errorMessage">A description of the error</param> /// <returns>The HL7 acknowledgement</returns> public static HL7Acknowledgement AcknowledgeUnparseableMessage(string errorMessage) { HL7Separators typical = new HL7Separators(); HL7Acknowledgement ack = new HL7Acknowledgement(); ack.MessageHeader = new MSH(); ack.MessageHeader.FieldSeparator = typical.FieldSeparator.ToString(); ack.MessageHeader.EncodingCharacters = typical.EncodingCharacters; ack.MessageHeader.SendingApplication = new HD() { namespaceID = "HIPS" }; ack.MessageHeader.SendingFacility = new HD() { namespaceID = "HIPS" }; ack.MessageHeader.ReceivingApplication = new HD() { namespaceID = "HIPS" }; ack.MessageHeader.ReceivingFacility = new HD() { namespaceID = "HIPS" }; ack.MessageHeader.DateTimeOfMessage = new TS() { TimestampValue = DateTime.Now }; ack.MessageHeader.MessageControlID = NewMessageControlID(); ack.MessageAcknowledgement = new MSA(); ack.MessageAcknowledgement.AcknowledgmentCode = "AE"; ack.MessageAcknowledgement.ErrorCondition = new CE() { text = errorMessage }; return(ack); }
internal static void Encode(HL7Separators seps, System.Text.StringBuilder sb, Type type, object value) { // A component is either empty, a string or an HL7 data structure containing subcomponents. if (value == null) { // Do nothing } else if (value is string) { sb.Append(seps.Encode(value as string)); } else { foreach (FieldInfo subcomponent in type.GetFields()) { // A subcomponent is always a string sb.Append(seps.Encode(subcomponent.GetValue(value) as string)); sb.Append(seps.SubcomponentSeparator); } // Remove the extraneous subcomponent separator sb.Remove(sb.Length - 1, 1); } }