HL7Find is an HL7 v2 parsing library that uses typical HL7 location notation as a means of retrieving values.
This library is not for sending or receiving HL7.
It's distinguishing feature is that it uses common (with some extensions) notation to access and update HL7 v2 messages. For example, to access PID.3.1 simply use my_message.find('PID.3.1')
instead of inventing syntax in the programming language.
This library is written using only the standard library for python 3. You can install it like most python packages:
pip install hl7find
The library is primarly a single class which takes an HL7 string (\r
or \n
delimeters on the segments) as its first argument.
There is also no need to specify the delimerters, repeating operator, or esacape character. HL7 does that in the MSH segment.
from hl7find import HL7Message
hl7_string = """
MSH|^~\&|SendingApp|SendingFac|ReceivingApp|ReceivingFac|20120411070545||ORU^R01|59689|P|2.3
PID|1|12345|12345^^^MIE&1.2.840.114398.1.100&ISO^MR||MOUSE^MINNIE^S||19240101|F|||123 MOUSEHOLE LN^^FORT WAYNE^IN^46808|||||||||||||||||||
OBX|1|NM|wbc^Wbc^Local^6690-2^Wbc^LN||7.0|/nl|3.8-11.0||||F|||20120410160227|lab|12^XYZ LAB|
OBX|2|NM|neutros^Neutros^Local^770-8^Neutros^LN||68|%|40-82||||F|||20120410160227|lab|12^XYZ LAB|
OBX|3|NM|lymphs^Lymphs^Local^736-9^Lymphs^LN||20|%|11-47||||F|||20120410160227|lab|12^XYZ LAB|
ZF1|TEST|REPEAT 1~REPEAT 2~REPEAT 3|This^Still^Works|deeper^repeat^1~deeper^repeat^2|other^deepest~repeating~field|z end
"""
msg = HL7Message(hl7_string)
With an HL7Message
instance you can use the find function to retrieve parts of the message. Using the example HL7 message above, this includes simple descrete values:
msg.find("PID.3.1") # -> 12345
msg.find("PID.3.4.1") # -> MEI
Repeating segments or values:
msg.find("OBX*.3") # -> A tuple of all obx segments at position 3
msg.find("ZF1.2") # -> The repeating field at ZF1.2 as a tuple: ('REPEAT 1', 'REPEAT 2'...)
msg.find("ZF1.4*.3") # -> The third position of the repeating value at ZF1.4: ('1','2')
msg.find("OBX[3].1") # -> The third obx segment and its value at position 1: 3
If you want to count from the opposite direction you can use a negative position value:
msg.find("MSH.-1") # -> The last position on the MSH segment: 2.3
If there is a repeating field or segment but your search string is ambiguous it will raise HL7AmbiguousSegmentException
.
Components of the HL7 message can be changed using the same find syntax. The one exception is repeating fields. These need to be changed on the level they repeat.
To change a field value just reference it and provide the updated value:
msg.update("MSH.2","New Facility")
msg.find("MSH.2") # -> "New Facility"
msg.update("PID.-1","last element")
msg.find("PID.-1") # -> "last element"
This works with specific segments when there are multiple.
msg.update("OBX[1].1","Yay!")
msg.find("OBX[1].1") # -> "Yay!"
You can also update part of a segment that isn't there yet and the structure will be extended to accomidate the update.
msg.update("MSH.100","added elements automatically")
msg.find("MSH.100") # -> "added elements automatically"
msg.update("PID.3.12","added elements")
msg.find("PID.3.12") # -> "added elements"
It's also possible to update an entire segment at once or another part of a segment but adding to the structure. The internal structure of HL7Message
is a list of tuples(segment name
, segment structure
) and the segment structure is a list of lists. Repeating fields are represented as a tuple. You can access the internal structure via the internal_structure
function.
When updating a segment or a more complex component of a segment all at once you can reflect this same internal structure and delimeters will be placed accordingly when outputting with to_string
.
msg.update("ZF1",['test','a','value',['a','sub','value'],('and','a','repeating','field')])
msg.find("ZF1.1") # -> 'test'
msg.find("ZF1.4.2") # -> 'sub'
msg.find("ZF1.5[3]") # -> 'repeating'
It's also possible to add a segment that doesn't exist. Use the add_segment
function providing the segment name followed by the initial values. You can also specify a third argument of where (1-N) in the list of segments it should be inserted. It will not override the existing segment of that position but instead move the trailing segments (including the one at the specified index) down one index. The function will not take index 0 as an option as this should already be an MSH segment which is how a message must start.
msg.add_segment("ZBS",['new','segment',['with','initial','values']]) # -> adds the ZBS segment to the last position
msg.add_segment("ZCS",['another','segment','right','after','msh'], 1) # -> adds the ZCS segment as the second segment (right after msh)
HL7Message
s can be turned back into an HL7 string with the to_string
function which takes an optional keyword parameter to set the newline/break character (newline_char='\r'
)
Also, as updates cause mutation there a copy of an HL7Message
object can be made using the copy
function.
Contributions are welcome via pull request.
To report issues use github issues.
There is a test.sh
file that sets the PYTHONPATH so that pytest runs successfully from the root of the project.