I’m on a V2-to-FHIR journey writing some code to support translation of V2 messages to FHIR.
Along the way, one of the challenges I have is getting the testing framework set up so that it’s easy to write assertions about conversions. HL7 Messages are full of dense text, which makes it hard to read, and even harder to sprinkle them through with assertions, so that:
- The assertions about the FHIR translation are close to the HL7 Message text for which they are made (making it easy to verify that the right assertions are present).
- The text is loadable from external resources, rather than written in code.
- The assertions are written in a language that’s easy to get parsing tools for, and
- The assertion language works well with FHIR.
So, the last two are what leads to FHIRpath, which is obvious when you think about it.
FHIRPath is already in use for validating FHIR Resources, so here we go, just validating a bundle of resources.
The next bit is about making HL7 messages easier to split into smaller pieces. For now, a segment is small enough. Segments are detectable by this regular expression pattern: /^[A-Z]{2}[A-Z0-9]/. Any line that begins with that is a segment. Great, now we’re writing a parser (really a stream filter).
Now what? Well, I need a way to identify assertions. Let’s use the @ character to introduce an assertion. Anything followed by @ at the start of a line is an assertion, and it can be followed by a FHIRPath and an optional comment. I suppose we could use # for comments, but FHIRpath already recognizes // comments, so I’ll go with that. Except that I have urls in my messages, and I don’t want to have https:// urls split up after //. So, I’ll make the rule that the comment delimiter is two // followed by at least one space character.
Now, I’ll borrow from some older programming languages and say that a terminal \ at the end of a line signals continuation of on the next line. And it would be nice if \ plus some whitespace was the same as ending the line with a \, so I’ll throw that in. And finally, let’s ignore leading and trailing whitespace on a line, because whitespace messes up messyages (yes, HL7 messages in text are messy).
Here’s an example of how this might look in a message file:
MSH|^~\&|\
TEST|MOCK|\
DEST|DAPP|\
20240618083101-0400||\
RSP^K11^RSP_K11|\
RESULT-01|\
P|2.5.1|||\
ER|AL|\
||||Z32^CDCPHINVS
@MessageHeader.count() = 1 // It has one message header
@MessageHeader.source.name = “TEST”
@MessageHeader.source.endpoint = “MOCK”
@MessageHeader.destination.name = “DEST”
@MessageHeader.destination.endpoint = “DAPP”
This is about where I’m at now. Even better would be:
MSH|^~\&|\
@MessageHeader.count() = 1 // It has one message header
TEST|MOCK|\
@MessageHeader.source.name = “TEST”
@MessageHeader.source.endpoint = “MOCK”
DEST|DAPP|\
@MessageHeader.destination.name = “DEST”
@MessageHeader.destination.endpoint = “DAPP”
20240618083101-0400||\
RSP^K11^RSP_K11|\
RESULT-01|\
P|2.5.1|||\
ER|AL|\
||||Z32^CDCPHINVS
I’ll get to that stage soon enough. I still have 9 more days to burn on automation. You can see though, how FHIRPath makes it easy to write the tests within your sample messages.