lib7 usage¶
This is a high level implementation for python3 of lib7. Source code of this implementation can be found here.
lib7 is a C implementation of an hl7 parser and composer. The parsing part has the goal of being resource and runtime efficient. The python3 implementation is an interface to this library for rapid prototyping and experimentation. This comes at a cost, runtime efficiency is not as good as with the C implementation (but it’s stil lfaster than a pure python implementation), however, writing code is much quicker.
You may use lib7.Message.__init__
or lib7.open_file()
to create a lib7.Message
Object for reading.
see Reading HL7 Files.
lib7.compose()
or lib7.Composer
will create an object
that let’s you manipulate a hl7 file. However, this method is slower and
is, therefore, not optimal when parsing many files without the need of
modifying the content. see Composing HL7 Files.
Understanding Addressing¶
You can either iterate trough all objects to find a node or you may use the get(addr) and set(addr, value) methods to get and set values. It is important to understand, that the HL7 structure actually has 6 hirarchy levels (most people forget FIELD repetitions ~ and SEGMENT repetitions, ie. multiple OBR segments).
MSH|...||||||||ORU&data^R01~rep1
MSH(1)-9(1).2.1 <--- all optional address values
^ ^ ^ ^ ^ ^
| | | | | +---- SUBCOMP
| | | | +------ COMPONENT
| | | +--------- FIELD (optional? FIXME set default to 1)
| | +----------- FIELDLIST
| +-------------- SEGMENT repetition (optional, defaults to 1)
+----------------- SEGMENT
MSH SEGMENT
| |||||||| FIELDLIST
... ~rep1 FIELD
ORU ^R01 COMPONENT
&data SUBCMP
Addressing in HL7 (as it is used) is often ambigous. The 2 cases where tis is true is by addressing SEGMENTs and FIELDs.
As an example:
REP|0|f1~rep1|f2
REP|1|f21|f2~rep2
Here we see the 2 repetitions:
a segment can occour multiple times in a hl7 message (typically OBR) or in this case REP
a field (typically delimited by | can have multiple repetitions delimited by ~
Often the value f1 is address by REP-2 but this would return f1~rep1 from the first line and f21 from the 2nd line. The correct addres to find f1 would be:
REP(1)-2(1)
or to find f21
REP(2)-2(1)
Reading HL7 Files¶
import lib7
msg = lib7.open("path/to/some/file.hl7")
# check what sort of message type this is, defined in MsH-9.1
msh91 = None
msh92 = None
try:
msh91 = msg.get("MSH-9.1")
print(msh91) # should print the content of the FIELD
except Hl7StructureException:
print("MSH-9.1 Not found)
try:
msh92 = msh91.next_sibling
except Hl7StructureException:
print("MSH-9.2 Not found)
root = msh92
while root.parent:
root = root.parent
# we have now found the top most node which is of type MESSAGE
# This node contains N segments in children
print(root.type) # prints: Type.MESSAGE
print("%r" % root) # prints: <MESSAGE (children: 2)>
print(root.num_children) # prints: 2
assert(root == msg) # same same but different (variable name)
# every node in the structure is an iterator which will
# iterate over all child nodes.
#
# This is the preferred way, because it is faster than first
# fetching all nodes via `n.children` and then looping over them.
for seg in root:
print("%r" % seg)
# prints: <SEGMENT MSH(1) (children: 18), MSH>
# <SEGMENT PID(1) (children: 1), PID>
print(seg.addr)
# prints: MSH(1)
# PID(1)
# or you may fetch a list of child ndoes like this:
children = root.children
# print the segment names
for c in children:
print(c.data) # prints: MSH, PID, ...
See also:
lib7.Message.get()
: get a node by addresslib7.Message.meta()
: hl7 metadata such as separators, see:lib7.Meta
lib7.Message.children
: a list of segments in this Messagelib7.Node.data
: the nodes data if it has no children ( num_children is 0)lib7.Node.addr
: string representation of the current node’s addresslib7.Node.parent
: the parent Node, None if there is no parentlib7.Node.children
: a list of child ndoeslib7.Node.next_sibling
: the next sibling of this ndoelib7.Node.previous_sibling
: the last sibling of this nodelib7.Node.first_child
: gets the first child Nodelib7.Node.last_child
: gets the last child Nodelib7.Node.child_at()
: get a specific child at position Nlib7.Node.num_children
: how many child ndoes are there ?lib7.Node.num_siblings
: how many siblings are there ?lib7.Node.type
: returns the typelib7.Type
lib7.Node
: every child of Message is a Node
Composing HL7 Files¶
With lib7.Composer
you get access to writing and creating hl7 files.
because lib7.Composer
derives from lib7.Message
,
all the above methods described in Reading HL7 Files are applicable.
import lib7
# open an existing file for modifying
msg = lib7.compose("path/to/some/file.hl7")
# will create segment: "XYZ|^&mydata\r"
msg.set("XYZ(1)-1.2.3, "mydata")
# now write the changed data
msg.write_file("path/to/some/other.hl7")
# if you do bulk editing over many files, it is a good
# idea to free memory like so:
del(msg)
# create an empty message.
msg = lib7.compose()
# this message will already contain an MSH segment, always,
# it's really needed
#
# now you can start adding stuff
msg.set("PID-3(1), "patientnumber")
del(msg)
See also:
lib7.Composer.set()
: set a node by address, it will be created if it doesn’t existlib7.Composer.write_file()
: write the created or modified filelib7.Message
: all the other methods inherited from Messagelib7.Node
: every child of Message is a Node