java解析HL7协议报文工具(v24版)

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头,调用:

message.getMSH().getFieldSeparator().setValue("|");
message.getMSH().getEncodingCharacters().setValue("^~\\&");

设置完可以调用msh里面的get方法来设置值,例如:

message.getMSH().getMsh11_ProcessingID().getProcessingID().setValue("P");
message.getMSH().getMsh17_CountryCode().setValue("CHN");

maven导入工具包:

<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>

后来因为接入的项目用到的协议和ca.uhn.hapi工具里面已经定义好的类所解析的报文结构不一致,所以需要自己去编写工具来自定义解析和生成相应的HL7报文,比如以下报文的RSP_ZP7在工具包里面没有相应的类结构对应(\r为回车):

MSH|^~\\&|PMI||01||20170719143120||RSP^ZP7|YY00000001|P|2.4|\rMSA|AA|YY00000001|[MsgInfo] Method Type: ZP7 -Success Flag: AA -MSG: success QueryPerson return message success.\rQAK||||0|0|0\rQPD|\rIN1|6|0|8\rQRI|15.014454851245674|3|

下面我写了几个工具类来实现方便调用,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|^~\\&|PMI||01||20170719143120||RSP^ZP7|YY00000001|P|2.4|\rMSA|AA|YY00000001|[MsgInfo] Method Type: ZP7 -Success Flag: AA -MSG: success QueryPerson return message success.\rQAK||||0|0|0\rQPD|\rIN1|6|0|8\rQRI|15.014454851245674|3|";

        co.hl7Text2Obj(resStr);
    }

}

展开阅读全文

没有更多推荐了,返回首页