java解析HL7协议报文工具 HAPI(SpringBoo
java解析HL7协议报文工具 因为项目需要解析HL7协议报文,网上找到的工具都是解析成带位置信息的xml格式或者json格式,然后需要自己根据需要获取的位置来获取信息。而在生成的HL7协议报文的时候也是需要先生成xml或json格式再进行转换。想着希望找到一个直接解析生成类然后直接用的工具。 后来我找到了这个ca.uhn.hapi,能将HL7报文直接解析成相应的类,通过调用:PipeParser.parse(message, hl7str)来解析报文,将数据填充到message类里面,其中message是工具里面的继承Message类的子类,例如:QBP_Q11、RSP_K23等。而生成HL7报文的时候又可以调用message.encode()来生成,不过需要先设置MSH头
一、依赖:
<dependency> <groupId>ca.uhn.hapi</groupId> <artifactId>hapi-base</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>ca.uhn.hapi</groupId> <artifactId>hapi-structures-v24</artifactId> <version>2.3</version> </dependency>
因为我们是通过socket对接实现的,先实现socket代码
1.启动类
@SpringBootApplication @EnableCaching @Configuration @EnableScheduling @ServletComponentScan @EnableTransactionManagement public class Application extends SpringBootServletInitializer { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(Application.class, args); SpringContextUtil.setApplicationContext(context); SocketServer demoServer = new SocketServer(); try { demoServer.start(); } catch (IOException e) { e.printStackTrace(); } } }
2.SocketServer(服务端)
@Component public class SocketServer{ private static final Logger logger = LoggerFactory.getLogger(SocketServer.class); public void start() throws IOException { ExecutorService newCacheThreadPool = new ThreadPoolExecutor( 2, 5, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy() ); ServerSocket server = new ServerSocket(SocketProperties.getSocketPort()); logger.info("socket服务端启动....端口:{}",SocketProperties.getSocketPort()); while (true) { final Socket socket = server.accept(); logger.info("开始处理请求"); newCacheThreadPool.execute(new Runnable() { @Override public void run() { try { handler(socket); } catch (Exception e) { e.printStackTrace(); } } }); } } private void handler(Socket socket) throws Exception { byte[] bytes = null; InputStream inputStream = null; try { inputStream = socket.getInputStream(); int bufflenth = inputStream.available(); while (bufflenth != 0) { bytes = new byte[bufflenth]; //读取数据(阻塞) inputStream.read(bytes); bufflenth = inputStream.available(); } String result = new String(bytes); result = new String(bytes).replaceAll("\n","\r") .replaceAll("\u000B","").replaceAll("amp;","").replaceAll("\u001c",""); logger.info("请求:{}" ,result); TestHL7.hl7Text2Obj(result,socket); } catch (IOException e) { e.printStackTrace(); } finally { logger.info("socket关闭"); try { inputStream.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
3.SocketClient
@Slf4j public class SocketClient { /** * 发送socket消息 */ public static String sendSocket(String message){ Socket socket = null; String result = ""; InputStream in = null; OutputStream out = null; try { socket = new Socket(SocketProperties.getSocketSendIp(),SocketProperties.getSocketSendPort()); in = socket.getInputStream(); out = socket.getOutputStream(); log.info("----------开始发送 MESSAGE-----------{}",message); out.write(message.getBytes(SocketConstants.UTF_8)); out.flush(); socket.shutdownOutput(); byte[] byteBuffer = new byte[8*1024]; in.read(byteBuffer); result = new String(byteBuffer); log.info("Received from Server message: " + result); result = result.replaceAll("\n","\r") .replaceAll("\u000B","").replaceAll("amp;","").replaceAll("\u001c",""); return result; }catch (Exception e){ log.error("发送socket消息失败",e); }finally { if(socket!=null) { try { socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(in!=null) { try { in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(out!=null) { try { out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } log.info("disconnected."); return result; } public static String handle(Socket socket,String message) throws IOException { InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); log.info("----------开始发送 MESSAGE-----------{}",message); out.write(message.getBytes(SocketConstants.UTF_8)); out.flush(); socket.shutdownOutput(); byte[] byteBuffer = new byte[8*1024]; in.read(byteBuffer); String result = new String(byteBuffer); log.info("Received from Server message: " + result); return result; }
4.socket.properties
socket.server.port=30038 socket.send.server.ip=192.168.254.216 socket.send.server.p
后来因为接入的项目用到的协议和ca.uhn.hapi工具里面已经定义好的类所解析的报文结构不一致,所以需要自己去编写工具来自定义解析和生成相应的HL7报文,比如以下报文的RSP_ZP7在工具包里面没有相应的类结构对应(\r为回车): 下面我写了几个工具类来实现方便调用,HL7Helper类主要是设置数据和获取数据,UserDefineComposite类用于自定义数据类型,UserDefineMessage类用于自定义message类型:
HL7Helper类:
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.model.AbstractComposite; import ca.uhn.hl7v2.model.AbstractPrimitive; import ca.uhn.hl7v2.model.AbstractSegment; import ca.uhn.hl7v2.model.Message; import ca.uhn.hl7v2.model.Type; import ca.uhn.hl7v2.model.Varies; import ca.uhn.hl7v2.parser.PipeParser; /** * @author SamJoke */ public class HL7Helper { private static Method method = null; static { try { method = AbstractSegment.class.getDeclaredMethod("add", Class.class, boolean.class, int.class, int.class, Object[].class, String.class); method.setAccessible(true); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } /** * 自定义添加AbstractSegment类的字段类型,然后可以用getFeild方法进行赋值,例子参考: * testSegmentAddFeildRequest() * * @param obj * AbstractSegment对象 * @param c * 数据类型 * @param required * 是否必填 * @param maxReps * 数组长度 * @param length * 字节长度 * @param constructorArgs * 构造器 * @param name * 字段名 * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException */ public static void segmentAddFeild(AbstractSegment obj, Class<? extends Type> c, boolean required, int maxReps, int length, Object[] constructorArgs, String name) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { method.invoke(obj, c, required, maxReps, length, constructorArgs, name); } public static void segmentAddFeild(AbstractSegment obj, Class<? extends Type> c, int maxReps, int length, Message msg) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { segmentAddFeild(obj, c, false, maxReps, length, new Object[] { msg }, "user define"); } public static void segmentAddFeild(AbstractSegment obj, Class<? extends Type> c, int length, Message msg) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { segmentAddFeild(obj, c, false, 1, length, new Object[] { msg }, "user define"); } // public static void segmentAddFeild(AbstractSegment obj, HL7DataType hl7DateType, Message msg) // throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { // segmentAddFeild(obj, hl7DateType.getCls(), false, hl7DateType.getMaxReps(), hl7DateType.getLength(), // new Object[] { msg }, "user define"); // } @SuppressWarnings("unchecked") public static <T> T getField(AbstractSegment obj, int pos, int index, Class<T> cls) throws HL7Exception { return (T) obj.getField(pos, index); } /** * 将hl7str协议报文转换为指定的Message类(可自定义),例子参考:testSegmentAddFeildResponse() * * @param msg * Message类型,如ADT_A01 * @param hl7str * HL7协议报文 * @throws HL7Exception */ public static void acceptResponse(Message msg, String hl7str) throws HL7Exception { PipeParser p = new PipeParser(); p.parse(msg, hl7str); } public static String getMsgValue(Message msg, String segName, int... ints) throws HL7Exception { return getMsgValue(msg, 0, segName, ints); } public static String getMsgValue(Message msg, Class<? extends AbstractSegment> segCls, int... ints) throws HL7Exception { return getMsgValue(msg, 0, segCls.getSimpleName(), ints); } /** * * 获取Message里面的数据,例子参考testGetMsgValue() * * @param msg * Message类型 * @param struIndex * AbstractSegment数组位,比如PID有重复多个的话需要自己设置位置,默认传0进去 * @param segName * AbstractSegment名,如PID、MSH等 * @param ints * 具体位置,如new int[]{3,2,3} * @return * @throws HL7Exception */ public static String getMsgValue(Message msg, int struIndex, String segName, int... ints) throws HL7Exception { AbstractSegment stru = (AbstractSegment) msg.get(segName, struIndex); int segPos = 0; int composIndex = 0; if (ints.length <= 0) { segPos = 0; composIndex = 0; } else if (ints.length == 1) { segPos = ints[0]; composIndex = 0; } else { segPos = ints[0]; composIndex = ints[1]; } Type itetype = stru.getField(segPos, composIndex); for (int i = 2; i < ints.length; i++) { if (itetype instanceof AbstractPrimitive) { break; } else if (itetype instanceof AbstractComposite) { AbstractComposite coms = (AbstractComposite) itetype; itetype = coms.getComponent(ints[i]); } } return itetype.encode(); } public static void setMsgValue(Message msg, String segName, String value, int... ints) throws HL7Exception { setMsgValue(msg, 0, segName, value, ints); } public static void setMsgValue(Message msg, Class<? extends AbstractSegment> segCls, String value, int... ints) throws HL7Exception { setMsgValue(msg, 0, segCls.getSimpleName(), value, ints); } public static void setMsgValue(Message msg, Object segCls, String value, int... ints) throws HL7Exception { setMsgValue(msg, 0, segCls.getClass().getSimpleName(), value, ints); } /** * * 设置Message里面的数据,例子参考testSetMsgValue() * * @param msg * Message类型 * @param struIndex * AbstractSegment数组位,比如PID有重复多个的话需要自己设置位置,默认传0进去 * @param segName * AbstractSegment名,如PID、MSH等 * @param value * 设置值 * @param ints * 具体位置,如new * int[]{3,2,3},需要注意这里的位置,要根据上面的segName类的init方法里面Type的排序和类型来确定,是否支持这样的定位(层级),若不支持则会抛异常, * @return * @throws HL7Exception */ public static void setMsgValue(Message msg, int struIndex, String segName, String value, int... ints) throws HL7Exception { AbstractSegment stru = (AbstractSegment) msg.get(segName, struIndex); int segPos = 0; int composIndex = 0; if (ints.length <= 0) { segPos = 0; composIndex = 0; } else if (ints.length == 1) { segPos = ints[0]; composIndex = 0; } else { segPos = ints[0]; composIndex = ints[1]; } Type itetype = stru.getField(segPos, composIndex); //用户自定义Type if(itetype instanceof Varies){ itetype = ((Varies) itetype).getData(); } if (ints.length == 2) { ((AbstractPrimitive) itetype).setValue(value); } for (int i = 2; i < ints.length; i++) { if (itetype instanceof AbstractPrimitive) { ((AbstractPrimitive) itetype).setValue(value); } else if (itetype instanceof AbstractComposite) { AbstractComposite coms = (AbstractComposite) itetype; itetype = coms.getComponent(ints[i]); if (i >= ints.length - 1) { if (itetype instanceof AbstractComposite) { coms = (AbstractComposite) itetype; ((AbstractPrimitive) coms.getComponent(0)).setValue(value); } else { ((AbstractPrimitive) itetype).setValue(value); } } } } } } 复制代码
UserDefineComposite类:
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import ca.uhn.hl7v2.model.AbstractComposite; import ca.uhn.hl7v2.model.DataTypeException; import ca.uhn.hl7v2.model.Message; import ca.uhn.hl7v2.model.Type; import ca.uhn.hl7v2.model.v24.datatype.ST; /** * 用户自定义Type,根据传不同的长度和Types来构建 * @author SamJoke */ public class UserDefineComposite extends AbstractComposite { /** * */ private static final long serialVersionUID = 1L; private static Class<? extends Type> defalutclass = ST.class; Type[] data = null; public UserDefineComposite(Message message) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { super(message); data = new Type[1]; Constructor<? extends Type> cons = defalutclass.getConstructor(new Class[] { Message.class }); data[0] = (Type) cons.newInstance(new Object[] { getMessage() }); } public UserDefineComposite(Message message, Type... types) { super(message); init(types); } @SuppressWarnings("rawtypes") public UserDefineComposite(Message message, Class... clss) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { super(message); init(clss); } @SuppressWarnings("rawtypes") public UserDefineComposite(Message message, int typeCount) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { super(message); Class[] clss = new Class[typeCount]; data = new Type[typeCount]; Constructor<? extends Type> cons = defalutclass.getConstructor(new Class[] { Message.class }); for (int i = 0; i < clss.length; i++) { data[i] = (Type) cons.newInstance(new Object[] { getMessage() }); } } private void init(Type... types) { data = new Type[types.length]; for (int i = 0; i < types.length; i++) { data[i] = types[i]; } } @SuppressWarnings({ "rawtypes", "unchecked" }) private void init(Class... clss) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { data = new Type[clss.length]; for (int i = 0; i < clss.length; i++) { Constructor<? extends Type> cons = clss[i].getConstructor(new Class[] { Message.class }); data[i] = (Type) cons.newInstance(new Object[] { getMessage() }); } } @Override public Type[] getComponents() { return data; } @Override public Type getComponent(int number) throws DataTypeException { try { return this.data[number]; } catch (ArrayIndexOutOfBoundsException e) { throw new DataTypeException("Element " + number + " doesn't exist (Type " + getClass().getName() + " has only " + this.data.length + " components)"); } } } 复制代码
UserDefineMessage类:
import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.model.AbstractMessage; import ca.uhn.hl7v2.model.DoNotCacheStructure; import ca.uhn.hl7v2.model.Structure; import ca.uhn.hl7v2.parser.DefaultModelClassFactory; import ca.uhn.hl7v2.parser.ModelClassFactory; /** * 用户自定义Message,@DoNotCacheStructure注解为了不进行缓存 * @author SamJoke */ @DoNotCacheStructure public class UserDefineMessage extends AbstractMessage { private static final long serialVersionUID = 1L; private static ASType[] types; private static ModelClassFactory fat = null; static { try { fat = new DefaultModelClassFactory(); } catch (Exception e) { e.printStackTrace(); } } public UserDefineMessage(ModelClassFactory factory) throws HL7Exception { super(factory); init(types); } public UserDefineMessage(ASType... types) throws HL7Exception { super(fat == null ? new DefaultModelClassFactory() : fat); setASTypes(types); init(types); } private void init(ASType... types) throws HL7Exception { for (int i = 0; i < types.length; i++) { this.add(types[i].c, types[i].required, types[i].repeating); } } public String getVersion() { return "2.4"; } public Structure getAS(String asName, Class<? extends Structure> asCls) { return getTyped(asName, asCls); } @SuppressWarnings("unchecked") public <T extends Structure> T getAS(Class<T> asCls) throws HL7Exception { return (T) get(asCls.getSimpleName()); } public static class ASType { Class<? extends Structure> c; boolean required; boolean repeating; public ASType(Class<? extends Structure> c, boolean required, boolean repeating) { this.c = c; this.required = required; this.repeating = repeating; } } private static void setASTypes(ASType... tys) { types = tys; } }
测试类:
import ca.uhn.hl7v2.HL7Exception; import ca.uhn.hl7v2.model.v24.datatype.CE; import ca.uhn.hl7v2.model.v24.message.QBP_Q11; import ca.uhn.hl7v2.model.v24.segment.DSC; import ca.uhn.hl7v2.model.v24.segment.ERR; import ca.uhn.hl7v2.model.v24.segment.IN1; import ca.uhn.hl7v2.model.v24.segment.MSA; import ca.uhn.hl7v2.model.v24.segment.MSH; import ca.uhn.hl7v2.model.v24.segment.PID; import ca.uhn.hl7v2.model.v24.segment.QAK; import ca.uhn.hl7v2.model.v24.segment.QPD; import ca.uhn.hl7v2.model.v24.segment.QRI; import ca.uhn.hl7v2.model.v24.segment.RCP; /** * @author SamJoke */ public class TestHL7 { static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); public void setHeader(MSH msh) throws DataTypeException{ String nowDate = sdf.format(new Date()); msh.getFieldSeparator().setValue("|");// 分隔符 msh.getEncodingCharacters().setValue("^~\\&");// MSH-2 msh.getMsh3_SendingApplication().getHd1_NamespaceID().setValue("01"); msh.getMsh5_ReceivingApplication().getHd1_NamespaceID().setValue("PMI"); msh.getDateTimeOfMessage().getTimeOfAnEvent().setValue(nowDate);// MSH-7 msh.getMsh10_MessageControlID().setValue(nowDate + new Random().nextInt(100));// MSH-10 msh.getMsh11_ProcessingID().getProcessingID().setValue("P"); msh.getMsh12_VersionID().getVersionID().setValue("2.4"); msh.getMsh15_AcceptAcknowledgmentType().setValue("AL"); msh.getMsh16_ApplicationAcknowledgmentType().setValue("AL"); msh.getMsh17_CountryCode().setValue("CHN"); msh.getMsh18_CharacterSet(0).setValue("UNICODE"); } public String getHL7Text() { QBP_Q11 qbp_q11 = new QBP_Q11(); MSH msh = qbp_q11.getMSH(); String msg = null; try { //MSH设置 HL7Helper.setMsgValue(qbp_q11, MSH.class,"QBP", 9,0,0); HL7Helper.setMsgValue(qbp_q11, MSH.class,"ZP7", 9,0,1); setHeader(msh); //QBP设置 QPD qbp = qbp_q11.getQPD(); HL7Helper.setMsgValue(qbp_q11, QPD.class, "ZP7", 1,0,0); HL7Helper.setMsgValue(qbp_q11, QPD.class, "Find Candidates", 1,0,1); HL7Helper.setMsgValue(qbp_q11, QPD.class, "HL7v2.4", 1,0,2); //设置用户自定义Type qbp.getQpd3_UserParametersInsuccessivefields().setData(new UserDefineComposite(qbp_q11, 3)); //新增Type类型为CE的字段 HL7Helper.segmentAddFeild(qbp, CE.class, 250, qbp_q11); HL7Helper.setMsgValue(qbp_q11, QPD.class, "0", 3,0,0); HL7Helper.setMsgValue(qbp_q11, QPD.class, "2558856", 3,0,1); HL7Helper.setMsgValue(qbp_q11, QPD.class, "0", 3,0,2); HL7Helper.segmentAddFeild(qbp, CE.class, 100, qbp_q11); HL7Helper.setMsgValue(qbp_q11, QPD.class, "SamJoke", 5,0,0); HL7Helper.segmentAddFeild(qbp, CE.class, 250, qbp_q11); SimpleDateFormat sdf01 = new SimpleDateFormat("yyyyMMddHHmmss"); SimpleDateFormat sdf02 = new SimpleDateFormat("yyyy-MM-dd"); HL7Helper.setMsgValue(qbp_q11, QPD.class, sdf01.format(sdf02.parse("1994-8-30")), 6,0,0); HL7Helper.segmentAddFeild(qbp, CE.class, 1, qbp_q11); HL7Helper.setMsgValue(qbp_q11, QPD.class, "M", 7,0,0); //RCP设置 HL7Helper.setMsgValue(qbp_q11, RCP.class, "I", 1,0,0); HL7Helper.setMsgValue(qbp_q11, RCP.class, "20", 2,0,0); HL7Helper.setMsgValue(qbp_q11, RCP.class, "RD", 2,0,1); HL7Helper.setMsgValue(qbp_q11, RCP.class, "R", 3,0,0); msg = qbp_q11.encode(); } catch (Exception e) { e.printStackTrace(); } return msg; } public void hl7Text2Obj(String responseStr) { try { ASType[] asTypes = new ASType[7]; asTypes[0] = new ASType(MSH.class,true,true); asTypes[1] = new ASType(MSA.class,true,true); asTypes[2] = new ASType(QAK.class,true,true); asTypes[3] = new ASType(QPD.class,true,true); asTypes[4] = new ASType(PID.class,true,true); asTypes[5] = new ASType(IN1.class,false,true); asTypes[6] = new ASType(QRI.class,false,true); UserDefineMessage udm = new UserDefineMessage(asTypes); UserDefineMessage udm1 = new UserDefineMessage(asTypes); UserDefineMessage udm2 = new UserDefineMessage(asTypes); QPD qpd = udm2.getAS(QPD.class); HL7Helper.segmentAddFeild(qpd, CE.class, 250, udm2); // 添加一个长度为1的CE数组 HL7Helper.segmentAddFeild(qpd, CE.class, 250, udm2); // 添加一个长度为2的CE数组 HL7Helper.segmentAddFeild(qpd, CE.class, 2, 250, udm2); // 添加一个长度为1的CE数组 HL7Helper.segmentAddFeild(qpd, CE.class, 250, udm2); HL7Helper.acceptResponse(udm2, responseStr); MSH msh = (MSH) udm2.get("MSH"); System.out.println(msh.encode()); System.out.println(msh.getDateTimeOfMessage().getTs1_TimeOfAnEvent().toString()); QPD qpdt = (QPD) udm2.get("QPD"); System.out.println(qpdt.encode()); System.out.println(qpdt.getQpd1_MessageQueryName().getCe1_Identifier().getValue()); System.out.println(HL7Helper.getMsgValue(udm2, "QRI", 1,0,0)); System.out.println(udm2.encode()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { TestHL7 co = new TestHL7(); System.out.println(co.getHL7Text()); String resStr = "MSH|^~\\&|HALO|Mediinfo|MediII|Mediinfo|20220829141621||ORM^O01^ORM_O01|bba39c9f0da54bd4b0aef102bba0685d|P|2.4\r" + "PID||7748577|7748577^^^JG01~330212SYB0000278595^^^JG06~~~~330212SYB0000278595^^^JG06~33020099000000000022700386^^^JG07~SYB0000278595^^^JG08~~16413536^^^JG10||ChenBinJun^陈斌均||19990522000000|1|||宁波骏潮信息技术有限公司^^330200^330000^^^H~^^^^^^W^宁波骏潮信息技术有限公司||^^01^^^^15057443642~^^02|||20^已婚||330283199905227218^^^01|330283199905227218|||01^汉族|浙江省宁波市|||90^农民||156^中国||||0\r" + "NTE|1|备注||^患者6月前可能因工作压力等失眠,表现为入睡困难、易醒,醒后难以入睡,日间疲劳、思睡,伴有担心多虑,有重复检查门窗,可达20余次,有间断情绪低落,兴趣减退,精力疲乏,悲观,无消极言行,否认打鼾,无安静状态下的双下肢不适。^^反复失眠 6月^神志清,定向力完整,接触主动,对答切题,记忆力下降,思维形式无异常,否认幻觉、妄想,情绪焦虑、低落,情感反应协调,意志行为减退,社会功能受损,自知力存在。\r" + "PV1|10|O||R|||10386^^杨璐|||12|||||0|||600|1205082153^10||SYB1101||||||||||||||||||1|||00812^1号楼2楼A区^^1&&1^1^宁波市第一医院(海曙)||20220829140706|||||||V\r" + "ORC|NW|2022082911621^^1038880068||2022082911621|IP||||20220829141347|||10386^^杨璐|00812^^^^^^^^心理门诊||||00812^心理门诊^1|||20^0^0^^^0\r" + "OBR|1|2022082911621||33918^JSWS-植物神经功能检查^^17^JSWS|0|||||||02020301^心理测试(海曙)^1|||0000033918&JSWS-植物神经功能检查||^^^^^^13957821050|周六下午休息,其余正常检查。|||||^20|17\r" + "DG1|1||^焦虑状态|焦虑状态\r" + "OBX|1|ST|OB01^既往病史||患者6月前可能因工作压力等失眠,表现为入睡困难、易醒,醒后难以入睡,日间疲劳、思睡,伴有担心多虑,有重复检查门窗,可达20余次,有间断情绪低落,兴趣减退,精力疲乏,悲观,无消极言行,否认打鼾,无安静状态下的双下肢不适。||||||F|||20220829141347\r" + "OBX|2|ST|OB02^主诉||反复失眠 6月||||||F|||20220829141347\r" + "OBX|3|ST|OB03^体格检查||神志清,定向力完整,接触主动,对答切题,记忆力下降,思维形式无异常,否认幻觉、妄想,情绪焦虑、低落,情感反应协调,意志行为减退,社会功能受损,自知力存在。||||||F|||20220829141347"; co.hl7Text2Obj(resStr); } }
注意:这里要注意 \n 换成 \r
一开始这个东西我也研究了好久,才发现根据节点去解析,一般都有文档
#java后端##程序员#