Introduction
For those of us unfortunate enough to have to deal with it, HL7 is a commonly encountered language used by medical systems to communicate with each other. It is what someone dreamed up way back when before XML was invented. Indeed, the most recent version of HL7 is XML. However, for those of us that still have to use older systems, it's an unwieldy and unfriendly language to deal with; message components are delimited using carriage returns, pipe symbols, tildes, and ampersands.
Since most applications use XML for data exchange, and XML is much nicer to deal with anyway, it would be helpful if there were an HL7 to XML conversion library that was freely available. Sadly, despite scouring the web, I have not found a (free) class or utility that can easily be integrated into applications. There are a few Java libraries, and one well known (excellent) commercial application, but nothing free and easy to use.
This article is v1 of my attempt at creating such a library. Please feel free to use and extend it - and most importantly, fix any bugs I've missed.
Using the code
A very simple HL7 message looks something like this:
MSH|^~\&|||||20080925161613||ADT^A05||P|2.6
This class and method simply produces an XML representation of the same message. Note that this class isn't nearly clever enough to know what type of HL7 message it is converting - it merely creates an XML version of it. The point is that you can then use XPath to retrieve the segment you want to use since you know its location. The HL7 above returned by this method would look like this:
<HL7Message>
<MSH>
<MSH.0>MSH</MSH.0>
<MSH.1>^~\&</MSH.1>
<MSH.2/>
<MSH.3/>
<MSH.4/>
<MSH.5/>
<MSH.6>20080925161613</MSH.6>
<MSH.7/>
<MSH.8>
<MSH.8.0>ADT</MSH.8.0>
<MSH.8.1>A05</MSH.8.1>
</MSH.8>
<MSH.9/>
<MSH.10>P</MSH.10>
<MSH.11>2.6</MSH.11>
</MSH>
</HL7Message>
It's a static class which returns an XML string (as a string; it could easily be modified to return an XmlDocument
instead).
Using the class
string sHL7asXml = HL7ToXmlConverter.ConvertToXml(myHL7string);
The full class looks like this:
public static class HL7ToXmlConverter
{
private static XmlDocument _xmlDoc;
public static string ConvertToXml(string sHL7)
{
_xmlDoc = CreateXmlDoc();
string[] sHL7Lines = sHL7.Split('\r');
for (int i = 0; i < sHL7Lines.Length; i++)
{
sHL7Lines[i] = Regex.Replace(sHL7Lines[i], @"[^ -~]", "");
}
for (int i = 0; i < sHL7Lines.Length; i++)
{
if (sHL7Lines[i] != string.Empty)
{
string sHL7Line = sHL7Lines[i];
string[] sFields = HL7ToXmlConverter.GetMessgeFields(sHL7Line);
XmlElement el = _xmlDoc.CreateElement(sFields[0]);
_xmlDoc.DocumentElement.AppendChild(el);
for (int a = 0; a < sFields.Length; a++)
{
XmlElement fieldEl = _xmlDoc.CreateElement(sFields[0] +
"." + a.ToString());
if (sFields[a] != @"^~\&")
{
string[] sComponents = HL7ToXmlConverter.GetComponents(sFields[a]);
if (sComponents.Length > 1)
{
for (int b = 0; b < sComponents.Length; b++)
{
XmlElement componentEl = _xmlDoc.CreateElement(sFields[0] +
"." + a.ToString() +
"." + b.ToString());
string[] subComponents = GetSubComponents(sComponents[b]);
if (subComponents.Length > 1)
{
for (int c = 0; c < subComponents.Length; c++)
{
string[] subComponentRepetitions =
GetRepetitions(subComponents[c]);
if (subComponentRepetitions.Length > 1)
{
for (int d = 0;
d < subComponentRepetitions.Length;
d++)
{
XmlElement subComponentRepEl =
_xmlDoc.CreateElement(sFields[0] +
"." + a.ToString() +
"." + b.ToString() +
"." + c.ToString() +
"." + d.ToString());
subComponentRepEl.InnerText =
subComponentRepetitions[d];
componentEl.AppendChild(subComponentRepEl);
}
}
else
{
XmlElement subComponentEl =
_xmlDoc.CreateElement(sFields[0] +
"." + a.ToString() + "." +
b.ToString() + "." + c.ToString());
subComponentEl.InnerText = subComponents[c];
componentEl.AppendChild(subComponentEl);
}
}
fieldEl.AppendChild(componentEl);
}
else
{
string[] sRepetitions =
HL7ToXmlConverter.GetRepetitions(sComponents[b]);
if (sRepetitions.Length > 1)
{
XmlElement repetitionEl = null;
for (int c = 0; c < sRepetitions.Length; c++)
{
repetitionEl =
_xmlDoc.CreateElement(sFields[0] + "." +
a.ToString() + "." + b.ToString() +
"." + c.ToString());
repetitionEl.InnerText = sRepetitions[c];
componentEl.AppendChild(repetitionEl);
}
fieldEl.AppendChild(componentEl);
el.AppendChild(fieldEl);
}
else
{
componentEl.InnerText = sComponents[b];
fieldEl.AppendChild(componentEl);
el.AppendChild(fieldEl);
}
}
}
el.AppendChild(fieldEl);
}
else
{
fieldEl.InnerText = sFields[a];
el.AppendChild(fieldEl);
}
}
else
{
fieldEl.InnerText = sFields[a];
el.AppendChild(fieldEl);
}
}
}
}
return _xmlDoc.OuterXml;
}
private static string[] GetMessgeFields(string s)
{
return s.Split('|');
}
private static string[] GetComponents(string s)
{
return s.Split('^');
}
private static string[] GetSubComponents(string s)
{
return s.Split('&');
}
private static string[] GetRepetitions(string s)
{
return s.Split('~');
}
private static XmlDocument CreateXmlDoc()
{
XmlDocument output = new XmlDocument();
XmlElement rootNode = output.CreateElement("HL7Message");
output.AppendChild(rootNode);
return output;
}
}
Points of Interest
This is my first article on The Code Project. The new version of HL7 (which always should've been written in XML) will make this class redundant, but I hope this is useful to people in the meantime.
I hate HL7! :-)
History
No history yet.