0

I have an HL7 message whose content I'm manipulating slightly with the terser.set() method. Once I've done that, I see in the debugger that it's been changed just how I want it, but I can't seem to get the whole message back intact. I've tried (for example):

HapiContext context = new DefaultHapiContext();
Parser      parser  = context.getGenericParser();
Message     message = parser.parse( MESSAGE );
Terser      terser  = new Terser( message );

terser.set( "/PID-2", "XXX XX XXXX" );

String fixedMessage = message.encode();

...which gets me close, however, lines (segment lines) that ended in just vertical bars (pipes) with no values in their fields come back trimmed (the vertical bars are simply dropped). I want the message to remain identical to what I put in (if also modified where I did it on purpose).

Russ Bateman
  • 18,333
  • 14
  • 49
  • 65
  • What I'm writing here is an operation on actual HL7 messages that my user wishes to modify or correct for whatever purpose suits him or her. In this test example, the modification is to obliterate the SSN. It could be for other reasons like modifying date formats, address corrections, etc. – Russ Bateman Feb 21 '17 at 19:34

1 Answers1

1

I think you need to use addForcedEncode in the ParserConfiguration.

Like

   @Test
   public void testSetManualRepetitions() {
    try {
        String m = "MSH|^~\\&|hl7Integration|hl7Integration|||||ADT^A01|||2.3|\r" +
                "EVN|A01|20130617154644\r" +
                "PID|1|465 306 5961||407623|Wood^Patrick^^^MR||19700101|1||||||||||\r" +
                "PV1|1||Location||||||||||||||||261938_6_201306171546|||||||||||||||||||||||||20130617134644|||||||||";

        HapiContext hc = new DefaultHapiContext();
        ExecutorService es = hc.getExecutorService(); // to avoid npe when closing context should be fixed https://sourceforge.net/p/hl7api/bugs/223/
        ParserConfiguration pc = hc.getParserConfiguration();
        PipeParser pipeParser = hc.getPipeParser();
        Message message = pipeParser.parse(m);
        Terser terser = new Terser(message);
        //Add first Address
        terser.set("/.PID-11(0)-1", "13 Oxford Road");
        terser.set("/.PID-11(0)-3", "Oxford");
        //Add second Address
        terser.set("/.PID-11(1)-1", "16 London Road");
        terser.set("/.PID-11(1)-3", "London");

        pc.addForcedEncode("PID-26-1"); // make sure PID has 26 fields
        System.out.println(message.encode().replaceAll("\r", "\r\n"));
        hc.close();
    } catch (HL7Exception e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

yields:

/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/bin/java -ea -Didea.launcher.port=7540 "-Didea.launcher.bin.path=/Applications/IntelliJ IDEA CE.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar:/Applications/IntelliJ IDEA CE.app/Contents/plugins/junit/lib/junit-rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/lib/tools.jar:/Users/thomas/git/Hapi-HL7-Terser/target/test-classes:/Users/thomas/.m2/repository/junit/junit/4.4/junit-4.4.jar:/Users/thomas/.m2/repository/ca/uhn/hapi/hapi-base/2.2/hapi-base-2.2.jar:/Users/thomas/.m2/repository/ca/uhn/hapi/hapi-structures-v21/2.2/hapi-structures-v21-2.2.jar:/Users/thomas/.m2/repository/ca/uhn/hapi/hapi-structures-v23/2.2/hapi-structures-v23-2.2.jar:/Users/thomas/.m2/repository/ca/uhn/hapi/hapi-structures-v24/2.2/hapi-structures-v24-2.2.jar:/Users/thomas/.m2/repository/ca/uhn/hapi/hapi-structures-v25/2.2/hapi-structures-v25-2.2.jar:/Users/thomas/.m2/repository/org/slf4j/slf4j-simple/1.6.0/slf4j-simple-1.6.0.jar:/Users/thomas/.m2/repository/org/slf4j/slf4j-api/1.6.0/slf4j-api-1.6.0.jar:/Users/thomas/.m2/repository/org/slf4j/log4j-over-slf4j/1.6.2/log4j-over-slf4j-1.6.2.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.hl7integration.hapi.tests.SetRepetitionsTerserTest,testSetManualRepetitions
68 [main] INFO ca.uhn.hl7v2.util.Home - hapi.home is set to /Users/thomas/git/Hapi-HL7-Terser/.
170 [main] INFO ca.uhn.hl7v2.VersionLogger - HAPI version is: 2.2
197 [main] INFO ca.uhn.hl7v2.VersionLogger - Default Structure libraries found for HL7 versions 2.1, 2.3, 2.4, 2.5, 
MSH|^~\&|hl7Integration|hl7Integration|||||ADT^A01|||2.3
EVN|A01|20130617154644
PID|1|465 306 5961||407623|Wood^Patrick^^^MR||19700101|1|||13 Oxford Road^^Oxford~16 London Road^^London|||||||||||||||
PV1|1||Location||||||||||||||||261938_6_201306171546|||||||||||||||||||||||||20130617134644

Technically you are not changing the message, you parse it to a Java object and encode it back to string. So that your output message looks like your input message. There could still be subtle differences afterwards (e.g. if your input message is dynamic).


From the docs (http://hl7api.sourceforge.net/configuring_hapi.html):

Forced Encoding

By default, when encoding a message HAPI will not encode any segments or fields that have no content and therefore have no semantic meaning in the message.

This can cause problems if you need to transmit a message to a system that expects certain empty content to be present in order to get "hints" about where in the message it is.

The addForcedEncode method may be used to add Terser paths which should be forced to be encoded:

parser.getParserConfiguration().addForcedEncode("PATIENT_RESULT/ORDER_OBSERVATION/ORC-4"); // ORC-4 will still exist (but be empty) even if ORC has no content String encoded = parser.encode(message); See the JavaDoc for examples.

ThomasW
  • 475
  • 3
  • 15
  • Thanks. The addForcedEncode() method makes no difference whatsoever. My input message is a string containing '\r'-separated lines. As I say, message.encode() yields an output of exactly what I want, including my change, except that segment lines (including the one I changed and all others that I did not change) ending in pipes (like |, || or ||||||||) no longer have those empty pipes left on them as if the mechanism has decided to trim them as if they were no more than white space. In my mind, I shouldn't have to read every segment, count the empty | and then add them back after. – Russ Bateman Feb 21 '17 at 19:27
  • 1
    I agree with you that you should not have to count and put back empty fields. But according to the HL7 standard the empty fields can be omitted and that is exactly how HAPI works. AddForcedEncode does work (as documented). I use it in my production code. I will put a complete example in an updated version of the answer. I would also like to "just change the damn message". – ThomasW Feb 26 '17 at 10:21