HL7解析器
最近做了关于医疗的项目,用了HL7协议,以下是解析的代码:
HL7解析器:
1 using System; 2 using System.Text; 3 using System.Xml; 4 using System.IO; 5 6 namespace CA2 7 { 8 /// <summary> 9 /// HL7解析器 10 /// </summary> 11 public static class HL7ToXmlConverter 12 { 13 private static XmlDocument _xmlDoc; 14 15 /// <summary> 16 /// 把HL7信息转成XML形式 17 /// 分隔顺序 \n,|,~,^,& 18 /// </summary> 19 /// <param name="sHL7">HL7字符串</param> 20 /// <returns></returns> 21 public static string ConvertToXml(string sHL7) 22 { 23 _xmlDoc = ConvertToXmlObject(sHL7); 24 return _xmlDoc.OuterXml; 25 } 26 27 public static XmlDocument ConvertToXmlObject(string sHL7) 28 { 29 _xmlDoc = CreateXmlDoc(); 30 sHL7 = sHL7.Replace("\\v","").Replace("\\u001c",""); 31 sHL7 = sHL7.Replace("\\r","\n"); 32 //把HL7分成段 33 string[] sHL7Lines = sHL7.Split('\n'); 34 35 ////去掉XML的关键字 36 //for (int i = 0; i < sHL7Lines.Length; i++) 37 //{ 38 // sHL7Lines[i] = Regex.Replace(sHL7Lines[i], @"[^ -~]", ""); 39 //} 40 41 for (int i = 0; i < sHL7Lines.Length; i++) 42 { 43 // 判断是否空行 44 if (sHL7Lines[i] != string.Empty) 45 { 46 string sHL7Line = sHL7Lines[i]; 47 //通过/r 或/n 回车符分隔 48 string[] sFields = HL7ToXmlConverter.GetMessgeFields(sHL7Line); 49 if (string.IsNullOrWhiteSpace(sFields[0]) == false) 50 { 51 // 为段(一行)创建第一级节点 52 if (string.IsNullOrWhiteSpace(sFields[0]) == false) 53 { 54 XmlElement el = _xmlDoc.CreateElement(sFields[0]); 55 _xmlDoc.DocumentElement.AppendChild(el); 56 // 循环每一行 57 for (int a = 0; a < sFields.Length; a++) 58 { 59 // 为字段创建第二级节点 60 XmlElement fieldEl = _xmlDoc.CreateElement(sFields[0] + "." + a.ToString()); 61 //是否包括HL7的连接符 62 if (sFields[a] != @"^~\&") 63 {//0:如果这一行有任何分隔符 64 //通过~分隔 65 string[] sComponents = HL7ToXmlConverter.GetRepetitions(sFields[a]); 66 if (sComponents.Length > 1) 67 {//1:如果可以分隔 68 for (int b = 0; b < sComponents.Length; b++) 69 { 70 XmlElement componentEl = _xmlDoc.CreateElement(sFields[0] + "." + a.ToString() + "." + b.ToString()); 71 //通过&分隔 72 string[] subComponents = GetSubComponents(sComponents[b]); 73 if (subComponents.Length > 1) 74 {//2.如果有字组,一般是没有的。。。 75 for (int c = 0; c < subComponents.Length; c++) 76 { 77 //修改了一个错误 78 string[] subComponentRepetitions = GetComponents(subComponents[c]); 79 if (subComponentRepetitions.Length > 1) 80 { 81 for (int d = 0; d < subComponentRepetitions.Length; d++) 82 { 83 XmlElement subComponentRepEl = _xmlDoc.CreateElement(sFields[0] + "." + a.ToString() + "." + b.ToString() + "." + c.ToString() + "." + d.ToString()); 84 subComponentRepEl.InnerText = subComponentRepetitions[d]; 85 componentEl.AppendChild(subComponentRepEl); 86 } 87 } 88 else 89 { 90 XmlElement subComponentEl = _xmlDoc.CreateElement(sFields[0] + "." + a.ToString() + "." + b.ToString() + "." + c.ToString()); 91 subComponentEl.InnerText = subComponents[c]; 92 componentEl.AppendChild(subComponentEl); 93 94 } 95 } 96 fieldEl.AppendChild(componentEl); 97 } 98 else 99 {//2.如果没有字组了,一般是没有的。。。 100 string[] sRepetitions = HL7ToXmlConverter.GetComponents(sComponents[b]); 101 if (sRepetitions.Length > 1) 102 { 103 XmlElement repetitionEl = null; 104 for (int c = 0; c < sRepetitions.Length; c++) 105 { 106 repetitionEl = _xmlDoc.CreateElement(sFields[0] + "." + a.ToString() + "." + b.ToString() + "." + c.ToString()); 107 repetitionEl.InnerText = sRepetitions[c]; 108 componentEl.AppendChild(repetitionEl); 109 } 110 fieldEl.AppendChild(componentEl); 111 el.AppendChild(fieldEl); 112 } 113 else 114 { 115 componentEl.InnerText = sComponents[b]; 116 fieldEl.AppendChild(componentEl); 117 el.AppendChild(fieldEl); 118 } 119 } 120 } 121 el.AppendChild(fieldEl); 122 } 123 else 124 {//1:如果不可以分隔,可以直接写节点值了。 125 fieldEl.InnerText = sFields[a]; 126 el.AppendChild(fieldEl); 127 } 128 } 129 else 130 {//0:如果不可以分隔,可以直接写节点值了。 131 fieldEl.InnerText = sFields[a]; 132 el.AppendChild(fieldEl); 133 } 134 } 135 } 136 } 137 } 138 } 139 return _xmlDoc; 140 } 141 142 /// <summary> 143 /// 通过|分隔 字段 144 /// </summary> 145 /// <param name="s"></param> 146 /// <returns></returns> 147 private static string[] GetMessgeFields(string s) 148 { 149 return s.Split('|'); 150 } 151 152 /// <summary> 153 /// 通过^分隔 组字段 154 /// </summary> 155 /// <param name="s"></param> 156 /// <returns></returns> 157 private static string[] GetComponents(string s) 158 { 159 return s.Split('^'); 160 } 161 162 /// <summary> 163 /// 通过&分隔 子分组组字段 164 /// </summary> 165 /// <param name="s"></param> 166 /// <returns></returns> 167 private static string[] GetSubComponents(string s) 168 { 169 return s.Split('&'); 170 } 171 172 /// <summary> 173 /// 通过~分隔 重复 174 /// </summary> 175 /// <param name="s"></param> 176 /// <returns></returns> 177 private static string[] GetRepetitions(string s) 178 { 179 return s.Split('~'); 180 } 181 182 /// <summary> 183 /// 创建XML对象 184 /// </summary> 185 /// <returns></returns> 186 private static XmlDocument CreateXmlDoc() 187 { 188 XmlDocument output = new XmlDocument(); 189 XmlElement rootNode = output.CreateElement("HL7Message"); 190 output.AppendChild(rootNode); 191 return output; 192 } 193 194 public static string GetText(XmlDocument xmlObject, string path) 195 { 196 XmlNode node = xmlObject.DocumentElement.SelectSingleNode(path); 197 if (node != null) 198 { 199 return node.InnerText; 200 } 201 else 202 { 203 return null; 204 } 205 } 206 207 public static string GetText(XmlDocument xmlObject, string path, int index) 208 { 209 XmlNodeList nodes = xmlObject.DocumentElement.SelectNodes(path); 210 if (index <= nodes.Count) 211 { 212 return nodes[index].InnerText; 213 } 214 else 215 { 216 return null; 217 } 218 } 219 220 public static String[] GetTexts(XmlDocument xmlObject, string path) 221 { 222 XmlNodeList nodes = xmlObject.DocumentElement.SelectNodes(path); 223 String[] arr = new String[nodes.Count]; 224 int index = 0; 225 foreach (XmlNode node in nodes) 226 { 227 arr[index++] = node.InnerText; 228 } 229 return arr; 230 231 } 232 233 public static string FormatXml(string sUnformattedXml) 234 { 235 236 XmlDocument xd = new XmlDocument(); 237 xd.LoadXml(sUnformattedXml); 238 StringBuilder sb = new StringBuilder(); 239 StringWriter sw = new StringWriter(sb); 240 XmlTextWriter xtw = null; 241 try 242 { 243 xtw = new XmlTextWriter(sw); 244 xtw.Formatting = Formatting.Indented; 245 xtw.Indentation = 1; 246 xtw.IndentChar = '\t'; 247 xd.WriteTo(xtw); 248 } 249 finally 250 { 251 if (xtw != null) 252 xtw.Close(); 253 } 254 return sb.ToString(); 255 } 256 } 257 }
程序入口:
using System; using System.Collections.Generic; using System.Xml; namespace CA2 { class Program { static void Main(string[] args) { String myHL7string = @"\vMSH|^~\\&||Mindray|||20191113163421||ORU^R01|2|P|2.3.1||||||UNICODE\rPID|1||^^^^MR||^患者名称|||男\rPV1|1||儿科\rOBR|1||7|00001^Automated Count^99MRC|||20191113102722|||单位||||||||||||||HM||||||||人员\rOBX|1|IS|08001^Take Mode^99MRC||C||||||F\rOBX|2|IS|08002^Blood Mode^99MRC||P||||||F\rOBX|3|IS|08003^Test Mode^99MRC||CBC+DIFF+CRP||||||F\rOBX|4|IS|01002^Ref Group^99MRC||儿童||||||F\rOBX|5|NM|30525-0^Age^LN||3|yr|||||F\rOBX|6|NM|6690-2^WBC^LN||10.62|10*9/L|4.00-12.00|N|||F\rOBX|7|NM|704-7^BAS#^LN||0.01|10*9/L|0.00-0.10|N|||F\rOBX|8|NM|706-2^BAS%^LN||0.1|%|0.0-1.0|N|||F\rOBX|9|NM|751-8^NEU#^LN||8.06|10*9/L|2.00-8.00|H~N|||F\rOBX|10|NM|770-8^NEU%^LN||75.8|%|50.0-70.0|H~N|||F\rOBX|11|NM|711-2^EOS#^LN||0.02|10*9/L|0.02-0.80|N|||F\rOBX|12|NM|713-8^EOS%^LN||0.2|%|0.5-5.0|L~N|||F\rOBX|13|NM|731-0^LYM#^LN||2.11|10*9/L|0.80-7.00|N|||F\rOBX|14|NM|736-9^LYM%^LN||19.9|%|20.0-60.0|L~N|||F\rOBX|15|NM|742-7^MON#^LN||0.42|10*9/L|0.12-1.20|N|||F\rOBX|16|NM|5905-5^MON%^LN||4.0|%|3.0-12.0|N|||F\rOBX|17|NM|789-8^RBC^LN||4.29|10*12/L|3.50-5.20|N|||F\rOBX|18|NM|718-7^HGB^LN||117|g/L|120-160|L~N|||F\rOBX|19|NM|787-2^MCV^LN||80.1|fL|80.0-100.0|N|||F\rOBX|20|NM|785-6^MCH^LN||27.2|pg|27.0-34.0|N|||F\rOBX|21|NM|786-4^MCHC^LN||339|g/L|310-370|N|||F\rOBX|22|NM|788-0^RDW-CV^LN||12.7|%|11.0-16.0|N|||F\rOBX|23|NM|21000-5^RDW-SD^LN||37.1|fL|35.0-56.0|N|||F\rOBX|24|NM|4544-3^HCT^LN||34.4|%|35.0-49.0|L~N|||F\rOBX|25|NM|777-3^PLT^LN||224|10*9/L|100-300|N|||F\rOBX|26|NM|32623-1^MPV^LN||8.7|fL|6.5-12.0|N|||F\rOBX|27|NM|32207-3^PDW^LN||16.3||15.0-17.0|N|||F\rOBX|28|NM|10002^PCT^99MRC||0.194|%|0.108-0.282|N|||F\rOBX|29|NM|30392-5^NRBC#^LN||0.002|10*9/L|0.000-9999.999|N|||F\rOBX|30|NM|26461-4^NRBC%^LN||0.02|%|0.00-9999.99|N|||F\rOBX|31|NM|10014^PLCR^99MRC||19.6|%|11.0-45.0|N|||F\rOBX|32|NM|10013^PLCC^99MRC||44|10*9/L|30-90|N|||F\rOBX|33|NM|26477-0^*ALY#^LN||0.00|10*9/L|0.00-0.20|N|||F\rOBX|34|NM|13046-8^*ALY%^LN||0.0|%|0.0-2.0|N|||F\rOBX|35|NM|10000^*LIC#^99MRC||0.00|10*9/L|0.00-0.20|N|||F\rOBX|36|NM|10001^*LIC%^99MRC||0.0|%|0.0-2.5|N|||F\rOBX|37|NM|71426-1^FR-CRP^LN||12.56|mg/L|0.00-4.00|H~N|||F\rOBX|38|NM|15001^WBC Histogram. Left Line^99MRC||13||||||F\rOBX|39|NM|15003^WBC Histogram. Middle Line^99MRC||36||||||F\rOBX|40|NM|15002^WBC Histogram. Right Line^99MRC||71||||||F\rOBX|41|NM|15004^WBC Histogram. Meta Length^99MRC||1||||||F\rOBX|42|NM|15009^WBC Histogram. Total^99MRC||7675||||||F\rOBX|43|ED|15008^WBC Histogram. BMP^99MRC|||F|\rOBX|59|NM|15208^WBC DIFF Scattergram. FSC-LOG dimension^99MRC||0||||||F\r\u001c\r"; Test(myHL7string); Console.ReadLine(); } static void Test(string myHL7string) { string sHL7asXml = HL7ToXmlConverter.ConvertToXml(myHL7string); XmlDocument xmlObject = HL7ToXmlConverter.ConvertToXmlObject(myHL7string); XmlNodeList allOBX = xmlObject.SelectNodes("//OBX"); int i = 1; List<OutAnalyzerResultItemDTO> listOutAnalyzerResultItemDTO = new List<OutAnalyzerResultItemDTO>(); var strSpecimenTime = HL7ToXmlConverter.GetText(xmlObject, "OBR/OBR.7"); OutAnalyzerResultDTO outAnalyzerResultDTO = new OutAnalyzerResultDTO() { FlowNum = int.Parse(HL7ToXmlConverter.GetText(xmlObject, "OBR/OBR.3")), SpecimenTime = DateTime.Parse(string.Format("{0}-{1}-{2} {3}:{4}:{5}", strSpecimenTime.Substring(0, 4), strSpecimenTime.Substring(4, 2), strSpecimenTime.Substring(6, 2), strSpecimenTime.Substring(8, 2), strSpecimenTime.Substring(10, 2), strSpecimenTime.Substring(12, 2))), }; foreach (XmlElement element in allOBX) { if (i >= 6 && i <= 37) { listOutAnalyzerResultItemDTO.Add(new OutAnalyzerResultItemDTO() { ItemCode = FormatItemCode(element.GetElementsByTagName("OBX.3")[0].InnerText),//项目对照编码 HLFlag = FormatFlag(element.SelectSingleNode("OBX.8/OBX.8.0"), element.SelectSingleNode("OBX.8")),//高低标记 ReferenceRange = element.GetElementsByTagName("OBX.7")[0].InnerText,//参考值 Result = element.GetElementsByTagName("OBX.5")[0].InnerText,//检测结果 Uint = element.GetElementsByTagName("OBX.6")[0].InnerText,//检测单位 }); } i += 1; } outAnalyzerResultDTO.resultItemDTOs = listOutAnalyzerResultItemDTO; listOutAnalyzerResultItemDTO.ForEach(x => { Console.Write("代码:" + x.ItemCode); Console.Write(" 结果:" + x.Result); Console.Write(" 参考值:" + x.ReferenceRange); Console.Write(" 单位:" + x.Uint); Console.WriteLine(" 高低值:" + x.HLFlag); }); } static string FormatItemCode(string allStr) { var a1 = allStr.IndexOf("^"); var a2 = allStr.LastIndexOf("^"); var aa = allStr.Substring(a1 + 1, a2 - a1 - 1); return aa; } static string FormatFlag(XmlNode str1, XmlNode str2) { return str1 == null ? str2.InnerText : str1.InnerText; } } }
DTO
public class OutAnalyzerResultItemDTO { public string ItemCode { get; set; } public string HLFlag { get; set; } public string ReferenceRange { get; set; } public string Unit { get; set; } public string Result { get; set; } }