Last active
August 29, 2015 14:10
-
-
Save FennyFatal/decec88912e89c4521eb to your computer and use it in GitHub Desktop.
Quick tool to build a node tree for a message in the HL7 standard.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Windows.Forms; | |
using System.Text.RegularExpressions; | |
namespace HL7Visualizer | |
{ | |
public class HL7 | |
{ | |
string[] rawMessage; | |
//These are the default values, we'll load them from the MSH line if there is one. | |
static char escape = '\\'; | |
static string delimiters = "|~^&"; | |
//These are characters that must be escaped to match them literally. | |
const string EscapeChars = @".$^{[(|)*+?\"; | |
/* | |
* These delimiters can be custom defined based on the needs of the HL7 user. | |
* Example: MSH|^~\& | |
* | is the field split | |
* ^ splits subfields | |
* ~ repeats a field | |
* \ is the escape char. | |
* & repeats a subfield. | |
* Order of operations would be: |~^& | |
* Finally we will remove each escape char immediately after the escaped delimiter has been processed. | |
* */ | |
private void parseMSH(string line) | |
{ | |
delimiters = String.Empty + line[3] + line[5] + line[4] + line[7]; | |
escape = line[6]; | |
} | |
public HL7() | |
{ | |
rawMessage = null; | |
} | |
public HL7(string[] lines) | |
{ | |
rawMessage = lines; | |
foreach (string line in rawMessage) | |
{ | |
// If we have a MSH line: | |
if (line.StartsWith("MSH")) | |
{ | |
parseMSH(line); | |
} | |
} | |
} | |
public HL7(string lines) | |
{ | |
rawMessage = lines.Split('\x0D'); | |
foreach (string line in rawMessage) | |
{ | |
// If we have a MSH line: | |
if (line.StartsWith("MSH")) | |
{ | |
parseMSH(line); | |
} | |
} | |
} | |
public static void PopulateNodes(TreeNodeCollection nodes, string[] lines) | |
{ | |
new HL7(lines).PopulateNodes(nodes); | |
} | |
public static void PopulateNodes(TreeNodeCollection nodes, string lines) | |
{ | |
new HL7(lines).PopulateNodes(nodes); | |
} | |
public void PopulateNodes(TreeNodeCollection nodes) | |
{ | |
nodes.Clear(); | |
foreach (string m in rawMessage) | |
{ | |
if (!m.Equals(String.Empty)) | |
//This function will recursively build our node tree. | |
nodes.Add(ParseChunks(-1, m, delimiters)); | |
} | |
} | |
private TreeNode ParseChunks(int index, string line, string delimiters) | |
{ | |
// If we are passed this line number we don't attach an index to the message. | |
bool rootnode = index == -1; | |
// Define our return value. | |
TreeNode retval = null; | |
// This is the last Parse. | |
if (delimiters.Length > 0) | |
{ | |
//Get the next delimiter | |
char delimiter = delimiters[0]; | |
//Consume a delimiter if there is only one set the string to empty. | |
if (delimiters.Length > 1) | |
delimiters = delimiters.Substring(1); | |
else | |
delimiters = String.Empty; | |
//Build the treenode with the contents of the line we were passed. | |
retval = new TreeNode((rootnode ? String.Empty : index.ToString() + " - ") + line); | |
if (rootnode && line.StartsWith("MSH")) | |
line = line.Replace("MSH|", @"MSH|\||"); | |
//Define the regex and escape our delimiters or escape character if required. | |
//We define a lookbefore for splitting when it is NOT our escape char: (?<!EscapeChar)DelimiterChar | |
string regex = @"(?<!" + (EscapeChars.Contains(escape) ? "\\" + escape : String.Empty + escape) + @")" + (EscapeChars.Contains(delimiter) ? "\\" + delimiter : String.Empty + delimiter); | |
//Split with a lookaround to make sure we trust escape chars. | |
string[] chunks = Regex.Split(line, regex); | |
//If there were no delimiters in the line there will be only one item in this array. | |
if (chunks.Length > 1) | |
{ | |
for (int i = 0; i < chunks.Length; i++) | |
{ | |
//Replace any escaped delimiters there may be. (We could do this in a seperate loop, but this is fewer cycles traded for duplication of code.) | |
chunks[i] = chunks[i].Replace(String.Empty + escape + delimiter, String.Empty + delimiter); | |
//Don't bother if we have an empty segment | |
if (!chunks[i].Equals(String.Empty)) | |
{ | |
//Recursively call with the new set of the delimiter queue. | |
retval.Nodes.Add(ParseChunks(rootnode ? i : i + 1, chunks[i], delimiters)); | |
} | |
} | |
} | |
else //We didn't have a match this time, but there are more delimiters to parse. | |
{ | |
//Replace any escaped delimiters there may be. | |
line = line.Replace(String.Empty + escape + delimiter, String.Empty + delimiter); | |
//Recursive call - We should return the next node so that we don't repeat ourselves. | |
retval = ParseChunks(index, line, delimiters); | |
} | |
} | |
else //No more delimiters, just return what we have. | |
{ | |
retval = new TreeNode(index.ToString() + " - " + line); | |
} | |
return retval; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment